  :root {
    /* ---- Lisbon ----------------------------------------------------------
       Azulejo supplies the geometry and the blues; conservas supply the heat.
       Ink is a deep green rather than a navy, so type ties to the nav instead
       of floating on it. SF runs the cobalt world, Guerneville the teal-and-
       gold one — see the per-house blocks below. */
    --ink:      #172F49;
    --tile:     #1B56A4;
    --tile-soft:#7FA9DA;
    --glaze:    #DCE8F4;
    /* Nudged from #FBF4DF once the motif came off the ground. Card-on-ground
       was 1.08:1, which was fine while the pattern marked the difference and
       far too close once it didn't — the shadow was doing all the lifting on
       its own. 1.14 here, and still limestone rather than grey. */
    --plaster:  #F6EED6;   /* warm cream — the page ground */
    --card:     #FFFDF6;   /* whitewash — content sits here */
    --ochre:    #96670F;   /* was #B8801A, which read 3.36:1 as text */
    --oxblood:  #B4472C;
    --sage:     #2E7D75;

    /* Record types carry their own colour, house-independent — a bill is a
       bill in either house. These drive the card edge, the check ring and the
       nav tile, so type is legible before a word is read. */
    --t-todo:   #DFA02B;
    --t-upkeep: #BE5029;   /* nudged darker: at #C4562F white text on it measured 4.45:1 */
    --t-bill:   #2E7D75;
    --t-meal:   #7B4E86;
    --t-doc:    #4E6E9E;
    --t-appt:   #2F6E4E;

    /* Retired. A lobby card now takes the colour of the destination it leads
       to, so Tonight is Calendar's indigo and cleaning is House's terracotta —
       both at 18% over card, which is the lightness this salmon had. */
    --latao:    #B98A38;   /* brass foil hairline */
    --rule:     rgba(var(--ink-rgb),.14);
    /* Muted body text. Measured, not eyeballed: .6 alpha came out at
       3.7:1 on card, under the 4.5:1 floor. */
    --ink-soft: rgba(var(--ink-rgb),.72);   /* 5.2:1 on card — muted body */
    --ink-mute: rgba(var(--ink-rgb),.68);   /* 4.7:1 on card — secondary    */
    /* Below this line the ink is decoration: rules, washes, disabled fills.
       Never put text on it. Seventeen different alphas were in play before
       this scale existed, and most of the text-bearing ones failed 4.5:1. */
    --ink-faint: rgba(var(--ink-rgb),.40);

    /* Each house gets a colour, so a glance tells you which one without
       reading the label. SF keeps the cobalt the app was built around;
       Guerneville takes a glazed green for the redwoods and the river.
       The -light pair is for use on the dark masthead. */
    --sf:        #2C5A87;
    --sf-light:  #6B93B4;
    --sf-wash:   rgba(44,90,135,.12);
    --sf-edge:   rgba(44,90,135,.38);

    --gv:        #2F7A5F;
    --gv-light:  #7FBFA3;
    --gv-wash:   rgba(47,122,95,.12);
    --gv-edge:   rgba(47,122,95,.38);

    /* The calendar's house grounds. Only the house you are NOT in gets one:
       days at the current house are plain card, so a tinted cell means "you
       are somewhere else that day" and its colour says where.

       That asymmetry is what lets these be this light. Tinting both houses
       meant the two tints had to be told apart from each other, and blue and
       green at equal alpha over the same ground land 1.04:1 apart — hue as
       the only channel, which is the trap the 7px house bars fell into.
       Against plain card instead, .13 measures 1.21:1 (SF) and 1.18:1 (GV):
       a smaller number doing a job it can actually do.

       Keyed on activeHouse() rather than state.baseHouse, so it follows the
       header chip and nothing here learns how many houses exist. */
    --cell-sf:   rgba(44,90,135,.13);
    --cell-gv:   rgba(47,122,95,.13);

    /* Today's ground. A higher alpha than the house tints for the same
       apparent weight — gold is a light hue, so .32 of it lands at 1.27:1
       against card where the house tints sit at 1.18–1.21.

       Fixed, like ochre and oxblood: today isn't a place, so it must not swap
       with the house. --today-line is the outline used when the selected day
       is also today; it clears 3:1 against both card and the gold ground,
       which a raw --t-todo outline would not (2.21:1). */
    --cell-today: rgba(223,160,43,.32);
    --today-line: #A9751A;

    /* Calendar day markers. Deliberately clear of ochre and oxblood so a
       planned dinner never wears the same colour as an overdue bill —
       except "something due", which is an attention state and should. */
    --mark-plan: var(--t-appt);
    --mark-meal: var(--t-meal);
    --mark-task: var(--t-todo);
    --mark-bill: var(--t-bill);

    /* Empty slots are drawn rather than hidden, so a day reads as four slots
       with some filled instead of a scatter whose meaning depends on counting
       positions. They have to sit far enough back that they never compete.

       .04 rather than .10: this is the level the out-of-month cells were
       already showing, since .mo-out fades the whole cell by .38 and .10 x
       .38 lands here. Those read as an empty slot; the full-strength ones
       read as a mark, which is wrong for something that means "nothing".
       At this level the ghost measures 1.07:1 on every ground the calendar
       uses — plain card, either house tint, today's gold — so it never
       becomes a mark on one kind of day and a texture on another.

       One value everywhere; a ghost that changes weight between views would
       read as a state rather than an absence. */
    --mk-ghost: rgba(var(--ink-rgb),.04);

    /* The week strip's house bars need to separate from each other, which is a
       different job from --sf/--gv, whose job is being legible as small text on
       white. Two dark saturated hues measure 1.39:1 against each other — near
       enough identical at 7px. Splitting them by lightness as well as hue
       gets 4.61:1. Text contrast isn't a concern here: these are blocks. */
    --bar-sf: #1B56A4;   /* cobalt */
    --bar-gv: #A8D8C6;   /* pale glaze green — 4.57:1 against the cobalt */

    /* The house you're currently in. render() sets data-house on <body> and
       these get swapped underneath everything that says "here". Defaults are
       the old cobalt, so anything not yet house-aware looks unchanged. */
    /* Text ON a filled house colour, the sibling of --dest-ink. White is
       right while the house colours are dark blues and greens, and wrong the
       moment a palette makes them bright — which is exactly what happened,
       so it is a token rather than a literal now. */
    --house-ink:   #fff;
    --house:       #2C5A87;
    --house-light: #6B93B4;
    --house-chip:  rgba(107,147,180,.18);
    --house-edge:  rgba(107,147,180,.5);

    /* Channel values for the same colours, so translucent tints can follow the
       theme too. Without these, half the app would stay blue at Guerneville —
       muted text, rules and washes are all derived from --ink and --glaze. */
    --ink-rgb:       23,47,73;
    --tile-rgb:      44,90,135;
    --tile-soft-rgb: 107,147,180;
    --glaze-rgb:     215,228,236;
    --tile-hover:    #24496E;

    /* The azulejo tile in the masthead. A data URI can't read a custom
       property from inside itself, so the whole url() swaps per house. */
    --masthead-pattern: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='56' viewBox='0 0 56 56'%3E%3Cg fill='none' stroke='%236B93B4' stroke-opacity='.22' stroke-width='1.4'%3E%3Cpath d='M28 6c6 8 14 16 22 22-8 6-16 14-22 22-6-8-14-16-22-22 8-6 16-14 22-22z'/%3E%3Ccircle cx='28' cy='28' r='5.5'/%3E%3Cpath d='M0 0h56v56H0z'/%3E%3C/g%3E%3C/svg%3E");

    /* The panel's tile band, drawn at 1:1 for a 14px strip. The masthead tile
       is a 56px motif, and scaling it into a 14px band rendered its 1.4px
       strokes at about a third of a pixel — present in the source, invisible
       on the glass. This one is sized for the band it lives in.

       Deliberately NOT per-house: the band takes --dest, so it's the room's
       colour, not the house's, and a white motif is the one that reads on all
       five. Adding a house doesn't need a new copy of this. */
    --band-pattern: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14'%3E%3Cg fill='none' stroke='%23FFFFFF' stroke-opacity='.45' stroke-width='1'%3E%3Cpath d='M7 1l6 6-6 6-6-6z'/%3E%3Cpath d='M0 0h14v14H0z'/%3E%3C/g%3E%3C/svg%3E");

    /* The frieze rule beside a section label — the second and last place the
       azulejo appears now that it is off the page ground. Its own tile rather
       than a scaled --masthead-pattern, for the reason --band-pattern exists:
       a 56px motif squeezed into 13px renders its strokes at a third of a
       pixel. Swaps per house like the others, since a data URI can't read a
       custom property from inside itself. */
    --frieze-pattern: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'%3E%3Cg fill='none' stroke='%23172F49' stroke-opacity='.30' stroke-width='1'%3E%3Cpath d='M6.5 1l5.5 5.5-5.5 5.5L1 6.5z'/%3E%3C/g%3E%3C/svg%3E");

    /* ---- the type ladder ----------------------------------------------
       Eleven rungs. There were 27 sizes before this, in half-point steps all
       the way from 9 to 15.5 — six of them doing the one chrome-label job and
       nine doing UI text. That is not a scale, it is a set of individually
       reasonable decisions each made against whatever happened to be next to
       it, which is how it reached 27. It had already started producing dead
       code: .sl-sub was declared at 12.5 and again at 13, both at top level,
       the first silently losing on source order.

       Named for the job rather than by t-shirt size, so the next element
       picks from a list of roles instead of picking a number. The faces are
       unchanged — serif for names, mono for figures and chrome labels, sans
       for UI — this only gives them somewhere to land. */
    /* The smallest chrome, and everything on it is width-constrained rather
       than merely small: seven day-of-week labels across a phone, and a type
       pill that has to sit beside a name without pushing it to two lines. */
    --fs-micro:     9.5px;
    --fs-label:    10.5px;   /* the chrome voice: heads, chips, subnav   */
    --fs-lead:     11.5px;   /* chrome that leads a card                 */
    --fs-body:       13px;   /* UI text, notes, links, mono meta         */
    --fs-large:      15px;   /* values, amounts, larger buttons          */
    /* Not a taste decision: iOS Safari zooms the page when a focused input is
       under 16px, and there is no way to opt out that doesn't also disable
       pinch-zoom. Anything the user types into stays here. */
    --fs-input:      16px;
    --fs-name:     17.5px;   /* record names                             */
    --fs-lead-name:  20px;   /* short-list names, week numbers           */
    --fs-title:      22px;   /* the front door's question, empty lines   */
    /* Fluid, because the complaint was proportional: 30px fills a third of
       a 375 phone and noticeably less of a 430 one, and Jenn reads it as
       the header having shrunk. 8.8vw keeps its share. The floor is the old
       value and the cap is set by the longest date — "Wednesday 30 Sep" is
       9.53x the font size, against (100vw - 36) of room, which 8.8vw clears
       at every phone width. */
    --fs-display:    clamp(30px, 8.8vw, 36px);   /* the date in the masthead */
    --fs-brand:      36px;   /* the wordmark, once a day                 */

    /* Relative on purpose, and the one value here that should be. Mono renders
       optically larger than sans at the same px, so a mono figure sitting
       inside a sans meta line needs shrinking to match it — and it has to
       track whatever that line is set to rather than naming a size of its
       own. */
    --fs-mono-inline: .92em;

    --serif: ui-serif, "New York", Georgia, "Times New Roman", serif;
    --ui: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
    --mono: ui-monospace, "SF Mono", Menlo, monospace;
  }

  * { box-sizing: border-box; }

  /* A short page used to leave the footer floating mid-screen. The column
     fills the viewport and the footer takes the slack, so it sits on the
     bottom whether there are two records or twenty. dvh rather than vh
     because mobile Safari's chrome makes vh taller than the screen. */
  html { min-height: 100%; }

  body {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
  }

  html, body {
    margin: 0;
    background: var(--plaster);
    color: var(--ink);
    font-family: var(--ui);
    -webkit-text-size-adjust: 100%;
  }

  /* The ground is plain plaster. It used to carry the azulejo motif, which
     was the single thing making the app read as a well-made document rather
     than as an app: content competed with its own wallpaper, and the card it
     sat in had to fight the pattern to be seen at all.

     The tile did not go away, it got concentrated — the masthead band, and a
     frieze rule beside a section label. Two places instead of everywhere, and
     it reads as tilework now rather than as texture on the paper.

     The empty states keep their own motif (.empty::before), which is where the
     "large empty areas read as unfinished" worry is actually answered. */
  body {
    padding-bottom: env(safe-area-inset-bottom);
  }

  /* Narrow is the base case — the app was phone-shaped long before it was
     anything else, and that's still the layout that matters most. Wider
     screens are handled by the media queries near the end of this stylesheet,
     which rearrange these same elements rather than replacing them. */
  /* `width: 100%` is load-bearing, and its absence was a real bug for as long
     as this rule has existed — visible only once the panel stopped being one
     opaque box that always filled its line.

     body is a column flex container, and `margin: 0 auto` sets the CROSS-axis
     margins to auto. An auto cross-margin disables `align-self: stretch`, so
     the wrap sized itself to its content and centred the result: Bills came
     out 188px wide inside a 393px phone, Calendar 337. The views that looked
     right were the ones whose widest row happened to fill the line.

     Giving it a definite width restores stretch and leaves the auto margins
     doing the job they were written for — centring the column once max-width
     caps it on a wide screen. */
  .wrap {
    width: 100%;
    max-width: 660px;
    margin: 0 auto;
    padding: 0 18px 72px;
    flex: 1;
    display: flex;
    flex-direction: column;
  }

  /* ---------- touch ----------
     The thing that made this feel like a document rather than an app: you
     could press anything and nothing acknowledged it. One treatment, applied
     once, to everything that takes a tap.

     Scale rather than colour, because colour here already means something —
     record type, house, destination, attention — and a press must not borrow
     any of those. It settles rather than bounces: no overshoot, no spring,
     because a bad day should not be met with something perky.

     `touch-action: manipulation` removes the 300ms double-tap delay iOS
     otherwise adds, which is half of why a web app feels slower than a native
     one. `-webkit-tap-highlight-color` removes the grey flash that would
     fight the treatment below. */
  button, .rec-open, .pick, .demand, .tab {
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
  }

  @media (prefers-reduced-motion: no-preference) {
    .btn, .rec-open, .sl-check, .rec-tick, .pick, .tab, .housechip,
    .linkish, .fd-level, .demand span, .planned-open, .sl-not, .step-tick {
      transition: transform .16s cubic-bezier(.2,.7,.3,1),
                  background-color .16s ease-out,
                  box-shadow .16s ease-out;
    }

    .btn:active, .pick:active, .fd-level:active, .housechip:active {
      transform: scale(.972);
    }

    /* A row is wide, so the same ratio would read as a lurch. */
    .rec-open:active, .planned-open:active { transform: scale(.988); }

    /* The rings are small and round; they take a firmer press. */
    .sl-check:active, .rec-tick:active, .step-tick:active { transform: scale(.9); }

    .demand input:active + span { transform: scale(.96); }
  }

  /* Not inside the motion query: a press must still register for someone who
     has asked for less movement. */
  .btn:active, .pick:active, .fd-level:active {
    background-color: color-mix(in srgb, var(--ink) 7%, var(--card));
  }

  .rec-open:active, .planned-open:active {
    background-color: color-mix(in srgb, var(--ink) 4%, transparent);
  }

  /* The send-off. Two beats: the ring fills with the record's own colour,
     then the row settles out of the way. Only ever plays on the way OUT, so
     nothing animates while you are reading — the list you open is already
     there, which is the difference between a page that lives and one that
     performs. */
  .is-settling .sl-check,
  .is-settling .rec-tick {
    background: var(--edge, var(--tile));
    border-color: var(--edge, var(--tile));
  }

  @media (prefers-reduced-motion: no-preference) {
    .is-settling .sl-check,
    .is-settling .rec-tick { transition: background-color .12s ease-out; }

    .is-settling {
      animation: settle .3s cubic-bezier(.32,0,.24,1) forwards;
      pointer-events: none;
    }

    @keyframes settle {
      40%  { opacity: 1; }
      to   { opacity: 0; transform: translateX(10px); }
    }
  }

  /* ---------- masthead ---------- */

  /* A band of tile over plaster, the way a Lisbon facade stacks. It used to
     be two bands with the wordmark cut into the upper one; the tile now runs
     behind the date instead, which is the same facade in half the height. */
  /* max(), because off a notched phone the inset is 0 and the date ended up
     flush against the top edge of the window. */
  .masthead {
    padding-top: max(env(safe-area-inset-top), 8px);
    background: var(--glaze);
  }

  /* The strip behind the Dynamic Island.

     `black-translucent` means the page runs under the status bar and iOS
     draws the clock and the battery in WHITE — which needs something dark
     beneath it. It used to get that by accident, from the cobalt frieze that
     happened to be the top of the page; with the frieze gone the masthead is
     pale glaze, and white on glaze is unreadable.

     Fixed rather than part of the masthead, so it holds when the page
     scrolls: otherwise whatever happens to scroll under the island decides
     whether the clock is legible. Above everything, the Front Door included,
     for the same reason. Zero height where there is no inset, so it costs
     nothing in a browser or on a Mac, and it takes --tile so it re-houses
     with the rest of the app. */
  .status-cap {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: env(safe-area-inset-top);
    background: var(--tile);
    z-index: 70;
    pointer-events: none;
  }

  /* The azulejo moves here from the band it lost. It was carrying the
     wordmark and is now carrying the masthead itself, so the tilework is
     structural rather than a strip above the content — the same motif, doing
     more work in less height. The brass hairline stays: it is the one edge in
     the app that reads as made rather than drawn. */
  .greet {
    background: var(--glaze);
    background-image: var(--masthead-pattern);
    background-size: 56px 56px;
    border-bottom: 2px solid var(--latao);
  }

  /* Wraps rather than squeezing, and the DATE is never the half that gives.
     A house could be called anything — the chip is built from state.houses
     and a third one joins without this knowing — so rather than trusting that
     every name stays short, the row is allowed to break and the date is not.
     The chip takes its own line on the rare occasion it must.

     This is the short list's head solved again by the same means: "the pill
     takes its own line for that one word and every other answer stays on
     one". Same problem, same answer, two mastheads apart. */
  /* THE DATE HAS ITS OWN ROW, which was Acid Garage's layout and is Jenn's.
     Sharing a line with the chip meant the date's budget depended on the DAY
     OF THE WEEK: at 375 the longest date is 286px against 256 available
     beside the chip, so "Wednesday" already pushed the chip down where
     "Tuesday" did not. A masthead that reflows on a Wednesday is a masthead
     you notice, which is the opposite of the job — and it is what capped the
     date's size, since anything larger reflowed on most days rather than a
     few.

     Given the full 339 the date can be bigger, which is what Jenn asked for
     off a photograph of her own phone. The chip moves down beside the
     greeting, where it belongs anyway: both of them qualify the day rather
     than announce it.

     `display: contents` on `.greet-text` is what keeps this a CSS-only
     change — it is a bare <div> with no styles and no semantics, so dropping
     it out of the box tree lets the date, the greeting and the chip be
     placed as one grid. */
  .greet-in {
    max-width: 660px;
    margin: 0 auto;
    padding: 18px 18px 19px;
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    column-gap: 14px;
    row-gap: 3px;
  }

  .greet-text { display: contents; }

  .today-row { grid-column: 1 / -1; }

  .hello {
    font-family: var(--serif);
    font-size: var(--fs-large);
    font-style: italic;
    line-height: 1.2;
    color: var(--ink-soft);
    margin-top: 3px;
  }

  /* Now the page's actual heading, and sized like one. It is the only thing
     in the masthead that changes, which is what a masthead is for. */
  .today {
    grid-column: 1 / -1;
    font-family: var(--serif);
    font-size: var(--fs-display);
    font-weight: 600;
    line-height: 1.05;
    letter-spacing: -.02em;
    color: var(--ink);
    margin: 0;
    white-space: nowrap;
  }

  /* A touch smaller than 16: at full size the tack out-weighed the two
     letters it qualifies.

     display MATTERS here. `.ico` is `display: block` because every other icon
     in the app sits alone inside an icon button — this is the first one that
     sits BESIDE text, and as a block it dropped to its own line inside the
     chip regardless of the chip's own `white-space: nowrap`, which only ever
     governs inline content. */
  .housechip .ico {
    display: inline-block;
    width: 13px;
    height: 13px;
    margin-left: 5px;
    vertical-align: -2px;
  }

  /* ---------- short list (signature) ---------- */

  /* The lobby. Jenn's structure: separate cards rather than rows under a
     shared rule, each carrying its record type as colour on three surfaces at
     once — the top edge, the check ring, the pill. Type registers before a
     word is read, which is the point on a day when reading is the expensive
     part. */
  /* The lobby had been three rounded floating cards with a coloured top edge —
     an idiom nothing else in the app used, which is why Today read as a
     different product. It's now one framed block in the same vocabulary as a
     panel: tile band on top, rows inside. The conservas frame (saturated
     border, brass hairline within) is what keeps it special without inventing
     a second design language. */
  /* A card like the others. It used to wear a 2px --dest frame with a brass
     hairline inside it, which worked while the ground was patterned — the
     frame was what lifted it off the wallpaper. On plain plaster it is the
     loudest object on the screen, and a double border is the one thing the
     card language rules out outright: radius and shadow already say "card",
     so a frame is a third voice saying it worse.

     What it cost is the short list looking more important than everything
     under it. That turns out to be fine — it is the first thing on the page,
     the only card above Tonight, and it has a head no other card has. */
  .shortlist {
    margin: 14px 0 22px;
    background: var(--card);
    border: 0;
    border-radius: 17px;
    overflow: hidden;
    /* Warm, not grey: a cool ink shadow on a plaster ground reads as dirt.
       Two layers — a contact edge and a cast — because one blur at one
       distance is what makes a shadow look printed on. */
    box-shadow:
      0 1px 2px rgba(120,86,40,.10),
      0 10px 22px -12px rgba(120,86,40,.30);
  }

  /* The brass hairline that makes it a tin label rather than a box. */
  .shortlist-inner { border: 0; margin: 0; }

  /* Wraps rather than squeezes. "Overwhelmed" is 11 characters and the rail
     is 286px: at full size the title and the pill genuinely do not both fit,
     and the failure mode without this was the title breaking mid-phrase
     ("SÓ TRÊS · JUST / THREE"), which looks broken rather than tight.

     Wrapping puts the pill on its own line for that one long word and leaves
     every other answer on one. The title never breaks, which is the part that
     matters — it's a brand element and a fixed phrase.

     Tried and rejected: shrinking both until they fit (works at exactly 6px
     of margin, so renaming any level would break it again), and moving the
     pill to the masthead beside the house chip (architecturally tempting —
     both are lenses on everything — but at 375px it pushes the serif date
     onto two lines, and that date is the most important thing up there). */
  .shortlist-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    row-gap: 7px;
    gap: 10px;
    padding: 12px 15px 11px;
    border-bottom: 1px solid var(--rule);
    background: color-mix(in srgb, var(--dest, var(--tile)) 8%, transparent);
  }

  .shortlist-title {
    white-space: nowrap;
    font-family: var(--mono);
    font-size: var(--fs-lead);
    font-weight: 700;
    letter-spacing: .15em;
    text-transform: uppercase;
    color: var(--dest-text, var(--dest, var(--tile)));
  }

  .shortlist-title b { font-weight: 500; color: var(--ink-soft); }

  /* Today's answer, in the chrome voice so it reads as state rather than as
     stray text. Ink rather than the room colour: it belongs to the day, not
     to the room you're standing in, and it must not compete with the title
     beside it. */
  .sl-day {
    flex: none;
    margin-left: auto;   /* stays right-aligned on the line it wraps onto */
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: .04em;
    color: var(--ink-soft);
    background: rgba(var(--glaze-rgb),.9);
    border: 1px solid rgba(var(--ink-rgb),.56);
    border-radius: 99px;
    padding: 3px 9px;
    min-height: 0;
    cursor: pointer;
    transition: color .13s ease-out, border-color .13s ease-out;
  }

  .sl-day:hover { color: var(--ink); border-color: rgba(var(--ink-rgb),.66); }

  /* Rows inside the frame, like every other list in the app. The record type
     still colours the check ring and the pill, so a bill still reads as a bill
     — that channel didn't need the card to carry it. */
  .sl-card {
    --edge: var(--tile);
    /* Named because three rules need the same two numbers: the gap, the ring
       itself, and the deferral menu, which has to start where the TEXT starts
       rather than at the card's own gutter. Writing 38px into that third one
       is the mistake the row separators already made — their first version
       hardcoded the phone's values and was 2px out above 620px within a
       minute. */
    --sl-ring: 26px;
    --sl-gap: 12px;
    position: relative;
    display: flex;
    /* So the deferral menu can take a line of its own under the row rather
       than the row becoming a column: the three children above it already
       fit on one line and are untouched by this. */
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--sl-gap);
    padding: 14px 15px 15px;
    border-bottom: 1px solid var(--rule);
  }

  .sl-card:last-child { border-bottom: 0; }

  .sl-todos, .sl-todo   { --edge: var(--t-todo); }
  .sl-maintenance       { --edge: var(--t-upkeep); }
  .sl-bills             { --edge: var(--t-bill); }
  .sl-docs              { --edge: var(--t-doc); }
  .sl-appts             { --edge: var(--t-appt); }

  /* The check is the primary action — a target you tick, not a button you
     read. It keeps its verb in the aria-label, which is where a bill's "Paid"
     and a landlord job's "Reported" survive the shape change. */
  /* Neutral, not the record's type colour. The ring is the biggest coloured
     object on a row and the most repeated element in the app, so spending it
     on type meant every row was coloured and colour stopped signalling. The
     type pill still carries type; what the ring gets back is the ability to
     mean one thing — an action you can take.

     It is NOT an urgency colour either, which was the other option and is
     worse: overdue is the normal state here, not the exception, which is the
     whole reason the lobby caps at three. A rust ring on every late item
     turns House into a wall of rust on exactly the week she can least look at
     it — the argument firmNow() vs nonDeferrable() already makes.

     rgba(--ink, .56) is the alpha this file already solved for control edges;
     as a ring it measures 3.47 in SF and 3.43 in Guerneville against the 3:1
     WCAG 1.4.11 asks of a control boundary. It re-houses on its own, so the
     ring stays ink rather than going neutral grey. */
  .sl-check {
    appearance: none;
    flex: none;
    width: var(--sl-ring);
    height: var(--sl-ring);
    margin-top: 2px;
    border: 2.5px solid rgba(var(--ink-rgb),.56);
    border-radius: 50%;
    background: transparent;
    cursor: pointer;
    padding: 0;
    min-height: 0;
    transition: background .13s ease-out;
  }

  .sl-check:hover { background: color-mix(in srgb, var(--edge) 18%, transparent); }

  /* The ring stays the size it looks; the target grows to 44px around it.
     This app is used one-handed, on a phone, on days when precision is the
     first thing to go. */
  .sl-check::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
  }

  .sl-check { position: relative; }

  .sl-body { flex: 1; min-width: 0; }

  /* The short list's type pill is .chip.chip-type in a .chips-top row — the
     look this rule used to own, now shared with every other surface. */

  .sl-name {
    font-family: var(--serif);
    font-size: var(--fs-lead-name);
    line-height: 1.22;
    font-weight: 600;
    letter-spacing: -.005em;
  }

  .sl-meta {
    font-family: var(--ui);
    font-size: var(--fs-body);
    margin-top: 4px;
    color: var(--ink-soft);
  }

  .sl-meta .chip { margin: 0 7px 0 0; }

  .sl-meta .late { color: var(--oxblood); }
  .sl-meta .soon { color: var(--ochre); }

  .sl-side {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    align-self: stretch;
    flex: none;
    gap: 8px;
  }

  /* margin-top:auto rather than space-between: appointments carry no house
     flag, and with a single child space-between pins it to the top. */
  .sl-side .sl-not { margin-top: auto; }

  .sl-side .chip { margin: 0; }

  /* Supplemental lines under the meta — prep, linked facts. Their own row
     because they're prose, and prose crammed onto a line of dates wraps into
     an orphan every time. */
  .sl-sub {
    font-size: var(--fs-body);
    line-height: 1.4;
    margin-top: 3px;
    color: var(--ink-soft);
  }

  .sl-not {
    background: transparent;
    border: 0;
    padding: 6px 2px 0;
    min-height: 0;
    font-family: var(--ui);
    font-size: var(--fs-body);
    color: var(--ink-soft);
    cursor: pointer;
  }

  .sl-not:hover { color: var(--ink); }

  /* 21px of text, 44px of target. */
  .sl-not { position: relative; }

  .sl-not::after {
    content: "";
    position: absolute;
    inset: -12px -8px;
  }

  /* The menu under "Not today", open on one to-do at a time. It expands in
     place for the reason the dinner picker does — there are no floating
     menus in this app, and a popup inside a 356px fixed rail is a
     positioning problem nothing else here has. */
  .sl-later {
    /* The basis takes the indent back out, or a full-width line plus a
       left margin overflows the card by exactly the margin. */
    flex: 0 0 calc(100% - var(--sl-ring) - var(--sl-gap));
    display: flex;
    flex-direction: column;
    /* Aligned to the text column, so the rule inside it marks a change of
       kind rather than running across the card underneath the ring — the
       same reason the row separators are inset to where their text starts.
       Derived from the two values above, never restated as a number. */
    margin-left: calc(var(--sl-ring) + var(--sl-gap));
    margin-top: 4px;
  }

  .sl-later-row {
    background: transparent;
    border: 0;
    /* 44, not the 40 the checkbox runs settled on: there the box is 22 and
       the rest was air, and here the whole row is the target. */
    min-height: 44px;
    padding: 0 2px;
    text-align: left;
    font-family: var(--ui);
    font-size: var(--fs-body);
    color: var(--ink-soft);
    cursor: pointer;
  }

  .sl-later-row:hover { color: var(--ink); }

  /* The one rule in here, and it marks a change of KIND: the row above it
     leaves the deadline alone, the rows below rewrite it. Not the hairline
     that came out of the form's checkbox runs — that separated three flags
     doing the same job, where the space was already the pause. */
  .sl-later-rule {
    height: 1px;
    background: var(--rule);
    margin: 2px 0;
  }

  /* Not a card — everything else is deliberately not competing for a slot. */
  /* An aside, in the voice the app already uses for asides — the greeting,
     the wordmark's "Casa", every "nothing planned". It had been a mono pill
     plus a sentence, which read as a third kind of chip on a card that
     already carries two, and sat on the card's own border. Right-aligned to
     answer the day pill in the head, ruled off so it reads as the end of the
     card rather than another row in it. */
  .sl-rest {
    border-top: 1px solid var(--rule);
    padding: 11px 15px 12px;
    text-align: right;
    font-family: var(--serif);
    font-style: italic;
    font-size: var(--fs-body);
    line-height: 1.35;
    color: var(--ink-soft);
  }

  /* "Nothing needs you today" is the message this app most wants to be able to
     deliver well — on a bad day it's the whole screen. Tilework behind it so
     an empty list reads as a finished, deliberate surface rather than a
     component that failed to load. */
  .empty {
    position: relative;
    padding: 34px 20px 36px;
    text-align: center;
  }

  /* Tilework around the edges, fading out behind the words. Laying it flat
     under the text made an empty list harder to read than a full one, which
     is exactly backwards for the screen you see on a bad day. */
  .empty::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image: var(--motif);
    background-size: 72px 72px;
    background-position: center;
    -webkit-mask-image: radial-gradient(ellipse 62% 58% at center, transparent 40%, #000 88%);
    mask-image: radial-gradient(ellipse 62% 58% at center, transparent 40%, #000 88%);
    pointer-events: none;
  }

  .empty-line {
    position: relative;
    font-family: var(--serif);
    font-size: var(--fs-title);
    font-style: italic;
    line-height: 1.3;
    color: var(--house);
  }

  .empty-sub {
    position: relative;
    font-size: var(--fs-large);
    line-height: 1.5;
    color: var(--ink-soft);
    margin: 9px auto 0;
    max-width: 34em;
  }

  /* ---------- drawer tabs ---------- */

  /* The navigation is the app's frame, not a control inside it: the same ink
     and the same tilework as the masthead it hangs from. The selected
     destination is a single pale tile lifted out of the pattern — which is
     also what replaces the coloured bar the active state used to wear. */
  .tabs {
    display: flex;
    gap: 3px;
    padding: 6px 6px 0;
    background: var(--ink);
    background-image: var(--masthead-pattern);
    background-size: 44px 44px;
    border-radius: 4px 4px 0 0;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }

  .tabs::-webkit-scrollbar { display: none; }

  .tab {
    appearance: none;
    border: 0;
    background: transparent;
    color: rgba(var(--glaze-rgb),.72);
    font-family: var(--ui);
    font-size: var(--fs-body);
    font-weight: 500;
    letter-spacing: .01em;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 13px 8px;
    border-radius: 3px 3px 0 0;
    cursor: pointer;
    flex: 1 0 auto;
    white-space: nowrap;
    min-height: 44px;
    transition: background .13s ease-out, color .13s ease-out;
  }

  .tab:hover { background: rgba(255,255,255,.09); color: var(--glaze); }

  .tab-tile {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 9px;
    background: color-mix(in srgb, var(--dest) 82%, transparent);
    color: #fff;
    flex: none;
  }

  .tab-ico { width: 19px; height: 19px; display: block; }

  :root[data-view="today"]    { --dest: var(--t-todo); --dest-ink: var(--ink);
                                --dest-text: #8A6012; }   /* gold reads 2.24:1 as text; this reads 5.48 */
  :root[data-view="house"]    { --dest: var(--t-upkeep); --dest-text: #A8441F; }
  :root[data-view="bills"]    { --dest: var(--t-bill);   --dest-text: #276B64; }
  /* Shopping takes the meal purple rather than a green of its own: --sage and
     --t-bill are the same teal, so Bills and Shopping were rendering as one
     room. Sharing with meals is the right accident anyway — the meal planner
     pulls straight into the grocery list, so they're genuinely the same
     errand. */
  /* Shopping was the one room with no --dest-text, so everything reading it
     fell through to `var(--dest, …)` — the meal purple used as TEXT, which is
     the trap --dest-text exists to prevent. It survived because that purple
     happens to be dark: #8A5A9C reads exactly 4.50 on plaster, passing AA by
     nothing at all, where its four siblings sit at 4.82–5.44. Latent rather
     than harmless — "Pull from this week's meals" and any frieze in this room
     were riding on a rounding. #82528F reads 5.10, which is the middle of the
     family, and 4.78 over the form's own wash. */
  :root[data-view="shopping"] { --dest: var(--t-meal); --dest-text: #82528F; }
  :root[data-view="calendar"] { --dest: var(--t-doc);    --dest-text: #42618E; }

  .tab[data-dest="today"]    { --dest: var(--t-todo); }
  .tab[data-dest="house"]    { --dest: var(--t-upkeep); }
  .tab[data-dest="bills"]    { --dest: var(--t-bill); }
  .tab[data-dest="shopping"] { --dest: var(--t-meal); }
  .tab[data-dest="calendar"] { --dest: var(--t-doc); }

  .tab[aria-selected="true"] {
    background: var(--card);
    color: var(--ink);
    font-weight: 600;
  }

  /* The panel is a container on the plaster, not a card. Cards are the
     grouping mechanism now: her upkeep and the landlord's are two cards, not
     one list with a heading partway down, and that grouping then survives
     scrolling instead of dissolving the moment the heading leaves the screen.
     groupIntoCards() in the script builds them out of what the panels already
     render, so no panel function knows about any of this. */
  .panel {
    background: transparent;
    border: 0;
    border-radius: 0;
    padding: 0;
    box-shadow: none;
  }

  /* 17px and a soft shadow rather than a hairline: the radius and the shadow
     are what say "card", and once they do a border is a third voice saying it
     worse. Warm shadow — a cool ink shadow on plaster reads as dirt.
     overflow clips the children that carry their own grounds (the .summary
     band, a row's hover), which would otherwise square the corners off and
     leave the radius present in the source and invisible on the glass. */
  .card {
    background: var(--card);
    border-radius: 17px;
    overflow: hidden;
    box-shadow:
      0 1px 2px rgba(120,86,40,.10),
      0 10px 24px -14px rgba(120,86,40,.30);
  }

  .card + .card,
  .subnav + .card,
  .note + .card { margin-top: 12px; }

  /* Chrome sits on the plaster, so it loses the edges it wore while it was
     inside a box: the subnav's underline rule, the note's band and hairline.
     The frieze and the label were already borderless. */
  .panel > .subnav { padding: 14px 3px 0px; }
  .panel > .note { border-bottom: 0; background: transparent; padding: 10px 3px 12px; }
  .panel > .section-head { padding-left: 3px; padding-right: 3px; }
  /* Descendant, not a child: groupIntoCards() wraps a label and its rows into
     a .group inside a .deck, so the label is two levels down now. */
  .panel .group-label { padding-left: 3px; padding-right: 3px; }
  .panel > .addbar { padding: 12px 0 4px; margin: 0 14px;  }

  /* The day the sections below are for. Serif rather than the friezes' mono,
     because it heads a run of them rather than labelling one band — and it
     lands where the week's house caption used to, so it costs no height. */
  .daysel {
    font-family: var(--serif);
    font-size: var(--fs-large);
    font-weight: 600;
    padding: 16px 3px 0;
  }

  /* "+ List" is an action sitting in a row of tabs, so it takes the tab's
     size and voice but never the selected underline. */
  .subnav-add { color: var(--dest-text, var(--dest, var(--tile))); }

  /* On the plaster now, under the filter bar. It had a hairline under it and
     16px of card padding either side, which made the only aggregate figure in
     the app read as the first record in the list. It is chrome — the same job
     the frieze beside it does — so it lost the rule and the card. */
  .summary {
    font-family: var(--mono);
    font-size: var(--fs-lead);
    color: var(--ink-soft);
    padding: 2px 4px 10px;
  }

  /* ---------- records ---------- */

  /* The most repeated element in the app, and until now the one place that
     opted out of every signature the system owns — no serif, no motif, no
     house colour. A list row is where a home-management app either feels
     designed or feels like a spreadsheet. */
  /* The separator starts where the TEXT starts, not at the card edge. A rule
     running underneath the check ring makes a row read as a cell in a table,
     and five of them stacked is a ladder — which is what "the run of rows
     within a card is undifferentiated" turned out to mean. Measured first:
     the spacing was already right (5px inside an item against 32px between
     them, a healthy 6:1), so the rows were not badly proportioned, they had
     no left edge to run down. Inset, the rings hang in a margin of their own
     and the list reads as items rather than as a grid.

     Carried on a variable so a row type sets its own inset rather than this
     rule knowing about rings: 14px of padding, a 23px ring and a 14px gap. A
     row with no ring keeps the plain padding, which is right — its text
     starts there. */
  .rec {
    /* Mirrors the padding rather than restating it as a number, so the three
       places that change the row's gutter — this rule, the phone override,
       and .is-firm's compensation — cannot drift from the separator. Hard
       numbers here were 2px out on the wide layouts within a minute of being
       written. */
    --pad-x: 16px;
    --ring-col: 0px;
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 15px 16px 16px;
    transition: background .13s ease-out;
  }

  .rec::after {
    content: "";
    position: absolute;
    left: calc(var(--pad-x) + var(--ring-col));
    right: 0;
    bottom: 0;
    border-bottom: 1px solid var(--rule);
    pointer-events: none;
  }

  /* The ring and the gap it sits in: 23px plus the row's own 14px. */
  .rec-check-row { --ring-col: 37px; }

  /* An absolutely-positioned child is placed against the PADDING box, which
     excludes the border — so on a firm row the separator would start 3px in
     from where its text does, indenting the rule on exactly the rows that are
     marked. The same 3px the padding already gives back. */
  .rec.is-firm::after { left: calc(var(--pad-x) - 3px + var(--ring-col)); }

  .rec:hover { background: rgba(var(--glaze-rgb),.34); }

  .rec:last-child::after { display: none; }
  .rec.done { opacity: .48; }

  .rec-body { flex: 1; min-width: 0; }

  /* The row's body opens it for editing. A button rather than a click handler
     on a div, so it's reachable by keyboard and announced as an action —
     everything inside is text, so nesting stays valid. */
  .rec-open {
    appearance: none;
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    font: inherit;
    color: inherit;
    text-align: left;
    width: 100%;
    min-height: 0;
    cursor: pointer;
    border-radius: 4px;
  }

  .rec-open:hover .rec-name { text-decoration: underline; text-decoration-color: rgba(var(--ink-rgb),.25); text-underline-offset: 3px; }
  .rec-open:focus-visible { outline: 2px solid var(--tile); outline-offset: 3px; }

  .stay-open { display: flex; align-items: baseline; gap: 10px; flex: 1; }

  /* Serif, matching the lobby. These are the same nouns — a bill, a task, an
     appointment — and there is no reason they should read as headlines on one
     screen and table rows on the next. */
  .rec-name {
    font-family: var(--serif);
    font-size: var(--fs-name);
    line-height: 1.28;
    letter-spacing: -.005em;
  }
  .rec.done .rec-name { text-decoration: line-through; }

  /* Sans for words, mono for figures. CLAUDE.md always said mono was for
     figures; the implementation had drifted into using it as a texture for
     every small thing, which is why every label in the app read the same and
     none of them read as data. Dates, amounts and measurements keep it. */
  /* Mono. "Mono for figures" was already the rule, and a row's meta line is
     very nearly all figures — dates, amounts, filter sizes, days waiting. In
     sans it read as body copy on a surface that carries none, and it was the
     one place the two faces disagreed with the short list beside it. */
  .rec-meta {
    font-family: var(--mono);
    font-size: var(--fs-body);
    line-height: 1.5;
    margin-top: 5px;
    color: var(--ink-soft);
  }

  /* The exceptions: lines that really are sentences rather than figures.
     .sl-sub is one, and it used to be listed here with a size as well — its
     own rule three hundred lines up declared 12.5px and this one 13px, both
     at top level, so the first lost on source order and nobody knew. Both are
     --fs-body now, so it only needs the face. */
  .rec-meta .prose { font-family: var(--ui); font-size: var(--fs-body); }
  .sl-sub { font-family: var(--ui); }

  /* Every span inside a meta line is a date, a time or a status reading —
     the measured part. The prose between them stays sans. */
  .rec-meta span,
  .sl-meta span {
    font-family: var(--mono);
    font-size: var(--fs-mono-inline);
  }

  .rec-meta .late { color: var(--oxblood); }
  .rec-meta .soon { color: var(--ochre); }
  .rec-meta .ok { color: var(--sage); }

  .amount {
    font-family: var(--mono);
    font-size: var(--fs-large);
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
    padding-top: 1px;
  }

  /* ---------- chips ----------
     One geometry for every small qualifier that hangs off a record, with a
     tone per job. Five genuinely different facts used to share two looks: a
     house, a record type, a plain property, an effort level, and the no-cook
     flag. An uncoloured chip sitting beside a green one read as a house you
     didn't recognise rather than as a different kind of fact. */
  .chip {
    display: inline-block;
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: .07em;
    text-transform: uppercase;
    border: 1px solid var(--rule);
    border-radius: 2px;
    padding: 1px 5px;
    color: var(--tile);
  }

  /* Chips never share a line with a name. A long name used to wrap them into
     a ragged tail, which is what made them read as debris rather than as
     data; their own row keeps every record the same shape whatever it's
     called. `chips-top` is the type pill above the name — a type classifies
     before you read, everything else qualifies what you just read. */
  .chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 6px; }
  .chips-top { margin: 0 0 7px; }

  /* A record's house is coloured by the house it belongs to, which may not be
     the house you're currently in — so this is per-element rather than keyed
     off the root attribute below. */
  .chip-sf { color: #1B4570; border-color: var(--sf-edge); background: var(--sf-wash); }
  .chip-gv { color: #256349; border-color: var(--gv-edge); background: var(--gv-wash); }

  /* The record's type, in that type's colour, which it inherits from the card
     or row it sits in. The fallback goes INSIDE var() — declaring `--edge`
     on this rule would set it on the chip and shadow the inherited value, so
     every pill would come out the same colour. */
  .chip-type {
    font-size: var(--fs-micro);
    font-weight: 700;
    letter-spacing: .12em;
    border: 0;
    border-radius: 99px;
    padding: 3px 9px;
    color: color-mix(in srgb, var(--edge, var(--tile)) 62%, var(--ink));
    background: color-mix(in srgb, var(--edge, var(--tile)) 16%, transparent);
  }

  /* Plain properties and states — autopay, here now, theirs. Quiet on
     purpose: they qualify a record without identifying or classifying it. */
  .chip-note { color: var(--ink-soft); border-color: var(--rule); }

  /* Effort is a scale, so it keeps three steps rather than collapsing to a
     note. Shown, never editorialised. */
  .chip-easy    { color: #1F5F55; border-color: rgba(31,95,85,.45); }
  .chip-some    { color: var(--tile); border-color: rgba(var(--tile-rgb),.4); }
  .chip-project { color: var(--ochre); border-color: rgba(150,103,15,.45); }

  /* Filled rather than outlined: on a bad day this is the one meal fact
     worth finding at a glance, so it doesn't read as another effort step. */
  .chip-nocook {
    color: #1F5F55;
    border-color: rgba(31,95,85,.45);
    background: rgba(31,95,85,.09);
  }

  /* ---------- "can't be put off", and actually due ----------
     A left rule and a faint wash, in the one pair of colours reserved for
     "this needs attention" — which is precisely what this is, so it's the
     reserved use rather than a breach of it. Oxblood doesn't swap with the
     house, for the documented reason: a signal that changes colour by
     location stops being one.

     Quiet about it. No bold, no caps, no icon, no size change, and the words
     never change — "was due Friday" reads the same on a ruled row as on any
     other. Language stays flat; this is weight, not volume.

     It stays rare by construction. Only the flag she set herself, and only
     once it's live — never every due bill, never every appointment, or it
     would light up half the list and stop meaning anything. Which is also
     why it is a row treatment and not a chip: the row already had a name, a
     type and a date to read, and a fourth thing to read is not how you make
     something easier to spot.

     The wash is 3% and that number is measured, not chosen. It sits behind
     the date, which is itself already an attention colour — ochre "due today"
     has only 4.86:1 to spend on card, so every point of wash comes straight
     out of the one line on the row with the least headroom. It crosses 4.5:1
     at six percent. The rule is what you actually see (5.32:1 against the
     panel); the wash only has to say "and the whole row, not just the edge". */
  .is-firm {
    border-left: 3px solid var(--oxblood);
    background: color-mix(in srgb, var(--oxblood) 3%, transparent);
  }

  /* Pull the left padding back by the width of the rule, so a ruled row's
     text sits on exactly the same line as an unruled one's. Without this the
     whole row shunts 3px right and reads as indented rather than marked. */
  .sl-card.is-firm { padding-left: 12px; }
  .rec.is-firm { padding-left: 13px; }

  /* ---------- a spectator's copy ----------
     Paul reads the house; he doesn't run it. The guarantee is elsewhere —
     replication is pull-only on a viewing device, and the click dispatcher
     drops anything not on an allow-list — so this is only about not offering
     a control that would do nothing. Failing to hide one is untidy; the
     wall behind it still holds.

     What stays is everything worth looking at: facts, recipes, upkeep,
     bills, the calendar, and every detail card. */
  :root[data-viewing] .sl-check,
  :root[data-viewing] .rec-tick,
  :root[data-viewing] .step-tick,
  :root[data-viewing] .sl-not,
  :root[data-viewing] .addbar,
  :root[data-viewing] [data-act="del"],
  :root[data-viewing] [data-act="delList"],
  :root[data-viewing] [data-act="edit"],
  :root[data-viewing] [data-act="undone"],
  :root[data-viewing] [data-act="starter"],
  :root[data-viewing] [data-act="choreStarter"],
  :root[data-viewing] [data-act="didChore"],
  :root[data-viewing] [data-act="clearDone"],
  :root[data-viewing] [data-act="clearTicked"],
  :root[data-viewing] [data-act="reported"],
  :root[data-viewing] [data-act="resolved"],
  :root[data-viewing] [data-act="plan"],
  :root[data-viewing] [data-act="oneOff"],
  :root[data-viewing] [data-goto],
  :root[data-viewing] #restoreBlock,
  /* Her answer to the Front Door. The ordering still reflects it, which is
     invisible and harmless; the word itself is hers to share, not the app's
     to put on someone else's home screen. */
  :root[data-viewing] .sl-day { display: none !important; }

  /* The check ring is gone, so the row closes the gap it left rather than
     keeping an empty indent that reads as something missing. */
  :root[data-viewing] .rec-check-row { padding-left: 16px; }
  :root[data-viewing] .sl-card { padding-left: 15px; }

  /* The way between today's cleaning list and the full one. A link rather
     than a tab: the full list is a reference you go and consult, not a second
     mode you work in. */
  /* Compound with .linkish on purpose: that rule sets padding: 0 and sits
     later in the file, so a bare .chores-all loses on source order and the
     link ends up flush against the panel edge. */
  .linkish.chores-all {
    display: block;
    width: 100%;
    /* Right, because it goes FORWARD — the same instinct the calendar's next
       arrow and the short list's "3 more" already answer. It reads as the way
       on rather than as another item in the list it sits under. */
    text-align: right;
    /* 14, not 16: the link is full-bleed on the plaster while the add bar
       above it is inset, and at 16 the text overhung the bar's right edge by
       two pixels — enough to read as not quite lined up on the one screen
       where they sit directly on top of each other. */
    padding: 15px 14px;
    font-size: var(--fs-body);
  }

  /* Back goes left, which is the other half of the same convention. Sharing
     .chores-all for everything else keeps the two links one thing with one
     difference, rather than two rules that have to be kept in step. */
  .linkish.chores-back { text-align: left; }

  /* The way into today's cleaning from the lobby. On the plaster under the
     add bar, styled as a link rather than a row, because it is a door and not
     an item — cleaning still never takes one of the three short-list slots. */
  .linkish.chores-link {
    display: block;
    width: 100%;
    text-align: left;
    padding: 14px 3px 0;
    font-size: var(--fs-body);
    color: var(--ink-soft);
    text-decoration: underline;
    text-decoration-color: rgba(var(--ink-rgb),.25);
    text-underline-offset: 3px;
  }

  /* A planned dinner is a record you can open, like every other name in the
     app. It sits inside a day row rather than on its own, so it takes the
     surrounding type rather than the record-name serif — the row already
     says what it is. */
  .planned-open {
    display: inline;
    width: auto;
    text-align: left;
    font: inherit;
    color: inherit;
    background: none;
    border: 0;
    padding: 0;
    min-height: 0;
    cursor: pointer;
  }

  .planned-open:hover {
    text-decoration: underline;
    text-decoration-color: rgba(var(--ink-rgb),.35);
    text-underline-offset: 3px;
  }

  /* A link in a reading view — the one place a detail value is something you
     go to rather than something you know. */
  .detail-link {
    color: var(--dest-text, var(--dest, var(--tile)));
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    overflow-wrap: anywhere;
  }

  .detail-link:hover { text-decoration-thickness: 2px; }

  /* Everything that reflects *where you are right now* hangs off one attribute
     on <body>, set in render(). Swapping four variables re-houses the whole
     app, so nothing downstream has to know a second house exists. */
  :root[data-house="sf"] {
    --motif: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='72' height='72' viewBox='0 0 72 72'%3E%3Cg fill='none' stroke='%23A8BDD0' stroke-opacity='.17' stroke-width='1'%3E%3Cpath d='M36 8c8 10 18 20 28 28-10 8-20 18-28 28-8-10-18-20-28-28 10-8 20-18 28-28z'/%3E%3Ccircle cx='36' cy='36' r='7'/%3E%3Cpath d='M0 0h72v72H0z'/%3E%3C/g%3E%3C/svg%3E");
    --house: var(--sf); --house-light: var(--sf-light); --house-text: #1B4570;
    --house-chip: rgba(44,90,135,.30); --house-edge: rgba(107,147,180,.55);
  }

  /* Guerneville runs the whole app on a green azulejo instead of the cobalt
     one — masthead, accents, rules, washes and the tile pattern. You know
     which house you're in before you've read a word.

     Note what deliberately does NOT change: ochre and oxblood. They mean
     "this needs attention", not "you are here", and a signal that shifts
     colour by location stops being a signal. */
  :root[data-house="gv"] {
    --ink:           #17352C;
    --ink-rgb:       23,53,44;
    --tile:          #1E5E52;
    --tile-rgb:      30,94,82;
    --tile-soft:     #8FC4B4;
    --tile-soft-rgb: 143,196,180;
    --glaze:         #CFE0D2;
    --glaze-rgb:     207,224,210;
    --plaster:       #F6EED6;
    --card:          #FFFDF6;
    --tile-hover:    #174B41;

    --motif: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='72' height='72' viewBox='0 0 72 72'%3E%3Cg fill='none' stroke='%23AECFBE' stroke-opacity='.17' stroke-width='1'%3E%3Cpath d='M36 8c8 10 18 20 28 28-10 8-20 18-28 28-8-10-18-20-28-28 10-8 20-18 28-28z'/%3E%3Ccircle cx='36' cy='36' r='7'/%3E%3Cpath d='M0 0h72v72H0z'/%3E%3C/g%3E%3C/svg%3E");

    --house: var(--gv); --house-light: var(--gv-light); --house-text: #256349;
    --house-chip: rgba(47,122,95,.30); --house-edge: rgba(127,191,163,.55);

    --masthead-pattern: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 48 48'%3E%3Cg fill='none' stroke='%238FC4B4' stroke-opacity='.48' stroke-width='1.5'%3E%3Cpath d='M24 2l6 16 16 6-16 6-6 16-6-16-16-6 16-6z'/%3E%3Ccircle cx='24' cy='24' r='5'/%3E%3Cpath d='M0 0h48v48H0z'/%3E%3C/g%3E%3C/svg%3E");

    --frieze-pattern: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 13 13'%3E%3Cg fill='none' stroke='%2317352C' stroke-opacity='.30' stroke-width='1'%3E%3Cpath d='M6.5 1l5.5 5.5-5.5 5.5L1 6.5z'/%3E%3C/g%3E%3C/svg%3E");
  }

  /* ---------- ACID GARAGE ------------------------------------------------
     An easter egg, and a deliberate holiday from the Lisbon brief rather than
     a revision of it. Jenn asked for it off a screenshot of Paul's TUI: "a
     sort of easter-eggy thing would be fun on days I want or need a little
     extra oomph". It is opt-in, per-device, and nothing reaches it by
     accident.

     It costs almost nothing to exist because the palette was already built to
     be swapped: this is the same move as adding a third house, one level out.
     The channel values (--ink-rgb and friends) are what make it possible at
     all — every wash, rule and muted text in the app derives from them, so
     inverting the base inverts the derived layer for free. Without those,
     half the app would have stayed cream.

     What does NOT relax, because it is not decoration:

     - Ochre and oxblood stay reserved and stay distinct from each other.
       They mean "this needs attention", and a theme that blurs them breaks
       the signal rather than restyling it.
     - The six record types stay tellable apart.
     - SF and GV still differ, so you know which house you are in before you
       read a word. Cyan and acid green here.
     - Contrast is measured, never eyeballed. The numbers are below. */

  :root[data-skin="acid"] {
    --ink:      #E6DAFF;
    --ink-rgb:  230,218,255;
    --plaster:  #150826;   /* the page ground */
    --card:     #1F0F38;   /* panels sit here */
    --tile:     #A24BF0;
    --tile-rgb: 162,75,240;
    --tile-soft:#C77DFF;
    --tile-soft-rgb: 199,125,255;
    --glaze:    #2A1250;
    --glaze-rgb: 42,18,80;
    --tile-hover: #B869FF;
    /* THE CHROME LINE TAKES THE OTHER HOUSE'S COLOUR, so the two signature
       hues always trade places: cyan date over a green rule at SF, green date
       over a cyan rule at Guerneville.

       Lisbon gets this for free — its brass is a THIRD colour, neither house,
       so "the brass hairline stays gold in both houses: it is brand, not
       location" holds trivially. Making --latao acid green here broke that
       without noticing, because acid green IS a house colour: at Guerneville
       the rule and the date were the same green and the line stopped reading
       as chrome at all.

       Jenn's fix keeps the INTENT — the chrome must never be confusable with
       the house signal — and reaches it the other way, by alternation rather
       than by standing outside. It is the one place this costume is
       deliberately location-dependent where Lisbon is not, and it works
       because there are two houses and the loud half is unambiguous: the date
       is 30px and the rule is 2. Per-house values are below. */
    --latao:    #B8F22D;

    /* ONE GROUND. --card is the same colour as --plaster here, which is the
       whole difference between this and a dark mode: a terminal has no filled
       panels, it has a field of text with rules drawn through it. Everything
       that was a box by virtue of being a lighter rectangle becomes a box by
       virtue of an outline, and the differentiation that was carried by tints
       moves onto the type. Jenn's note, and she was right — the first pass
       read as Lisbon after dark.

       --wire is the line that draws them. Cyan, because that is the colour
       doing the work in the screenshot this came from. */
    --card:     #150826;
    /* Near full strength. At .50 the wire measured 3.79:1 against the ground
       — past the 3:1 a control boundary asks for, and nowhere near what this
       costume is for. Jenn's brief was that it was "not forebrain-searing
       enough", which is the correct ambition for an easter egg and the wrong
       one for Lisbon, where the whole argument is that a border is a third
       voice saying what the radius and shadow already said.

       The separator comes up with it. It is the same cyan a step quieter, and
       leaving it at .22 under a .92 outline would have made the rows inside a
       card look unruled rather than deliberately quiet. */
    --wire:     rgba(61,232,240,.92);
    --rule:     rgba(61,232,240,.34);

    /* Attention, and still the only two colours that mean it. Kept a hue
       apart so they can never be confused for one another: 1.9:1 against
       each other, where the light theme's pair sits at 1.7. */
    --ochre:    #FFB627;
    --oxblood:  #FF4D6D;
    --sage:     #3DE8F0;

    /* Six types, six clearly different hues. The light theme's gold/
       terracotta pair is the one that gets closest, so they are pulled
       furthest apart here. */
    --t-todo:   #FFE14D;
    --t-upkeep: #FF8B3D;
    --t-bill:   #3DE8F0;
    --t-meal:   #E86BFF;
    --t-doc:    #7B9EFF;
    --t-appt:   #B8F22D;

    --sf:        #3DE8F0;
    --sf-light:  #8FF5FA;
    --sf-wash:   rgba(61,232,240,.14);
    --sf-edge:   rgba(61,232,240,.42);
    --gv:        #B8F22D;
    --gv-light:  #D6FA7A;
    --gv-wash:   rgba(184,242,45,.14);
    --gv-edge:   rgba(184,242,45,.42);
    --cell-sf:   rgba(61,232,240,.13);
    --cell-gv:   rgba(184,242,45,.13);

    /* Today is not a place, so it stays fixed here too. */
    --cell-today: rgba(255,225,77,.16);
    --today-line: #FFE14D;

    /* Blocks rather than hues, same as the light theme's bars. */
    --bar-sf: #3DE8F0;
    --bar-gv: #7B2FD6;

    --mk-ghost: rgba(var(--ink-rgb),.10);

    /* THE DESTINATION COLOURS ARE A SECOND AXIS, and their logic inverts
       here. On cream, --dest-text is a DARKENED --dest because the raw hue
       fails as type: "gold reads 2.24:1 as text; this reads 5.48". On this
       ground the bright hue is exactly what reads, and the darkened one is
       what does not — the frieze label measured 3.44:1, under the floor, and
       was the only thing in the app that did.

       So text takes the hue itself, and --dest-ink, which is text ON a filled
       --dest, becomes the dark ground rather than the light ink.

       One declaration covers all five rooms: the per-view blocks carry the
       same specificity and this comes later in the file. The fallback matters
       because the Front Door and Data & sync define no --dest at all, and an
       undefined custom property takes the whole declaration down with it. */
    --dest-text: var(--dest, var(--tile-soft));
    --dest-ink: var(--plaster);
    /* Same inversion, one axis over: the house colours are cyan and acid
       green here, and white on either is unreadable. */
    --house-ink: var(--plaster);

    /* Mono for everything, which is most of why it reads as a terminal
       rather than as a dark mode. Serif for names is the rule this breaks
       most loudly, and breaking it loudly is the point. */
    --serif: var(--mono);
    --ui: var(--mono);

    /* Blocks, not azulejo. The geometry is the other half of the costume. */
    --masthead-pattern: url("data:image/svg+xml;utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'32\' height=\'32\' viewBox=\'0 0 32 32\'%3E%3Cg fill=\'%23C77DFF\' fill-opacity=\'.30\'%3E%3Cpath d=\'M0 0h8v8H0zM16 0h8v8h-8zM8 8h8v8H8zM24 8h8v8h-8zM0 16h8v8H0zM16 16h8v8h-8zM8 24h8v8H8zM24 24h8v8h-8z\'/%3E%3C/g%3E%3C/svg%3E");
    /* SEGMENTS, off the telemetry bars in Paul's screenshot. Jenn's note was
       "I know they're progress bars, but they just look cool" \u2014 so they are
       the EMPTY half of one, uniformly. A frieze marks a change of kind and
       nothing more; filling some and not others would make it read as a
       measurement of the section under it, which is a number the app does not
       have and would be inventing. The texture is the point, not the meter.

       Outlined rather than solid, which is also what makes it read as a bar
       rather than as the dashes it replaced. */
    --frieze-pattern: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='13' viewBox='0 0 9 13'%3E%3Crect x='.8' y='1.9' width='4.4' height='9.2' fill='none' stroke='%23B8F22D' stroke-opacity='.85' stroke-width='1.3'/%3E%3C/svg%3E");
    --motif: none;
  }


  /* ---- Sakura ----------------------------------------------------------
     The third costume, and the first that came in as a SPEC rather than a
     brief: Jenn built six artboards, both houses and a token sheet with the
     contrast ratios already on it.

     THE GROUND IS NEUTRAL, NOT PINK, and that is the best decision in it.
     The warning going in was that a warm ground swallows warm signals —
     ochre and oxblood are the only two colours that mean "this needs
     attention", and on a pink page they slide into decoration. Her answer
     was to put the pink in the url("data:image/svg+xml;utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" width="480" height="330" viewBox="0 0 480 330"%3E%3Cdefs%3E%3Cg id="f"%3E%3Cg id="p"%3E%3Cpath d="M0 0C-6.5-4-7.5-12.5-4.2-17.5L0-15.2 4.2-17.5C7.5-12.5 6.5-4 0 0z"/%3E%3C/g%3E%3Cuse href="#p" transform="rotate(72)"/%3E%3Cuse href="#p" transform="rotate(144)"/%3E%3Cuse href="#p" transform="rotate(216)"/%3E%3Cuse href="#p" transform="rotate(288)"/%3E%3Ccircle r="3.4" fill="#E88AA2" stroke="none"/%3E%3Cg fill="#D9A23F" stroke="none"%3E%3Ccircle cy="-5.6" r="1"/%3E%3Ccircle cx="5.3" cy="-1.7" r="1"/%3E%3Ccircle cx="3.3" cy="4.5" r="1"/%3E%3Ccircle cx="-3.3" cy="4.5" r="1"/%3E%3Ccircle cx="-5.3" cy="-1.7" r="1"/%3E%3C/g%3E%3C/g%3E%3ClinearGradient id="fade" x1="0" y1="0" x2="0" y2="1"%3E%3Cstop offset="0" stop-color="#fff"/%3E%3Cstop offset=".40" stop-color="#fff"/%3E%3Cstop offset="1" stop-color="#000"/%3E%3C/linearGradient%3E%3Cmask id="m"%3E%3Crect width="480" height="330" fill="url(#fade)"/%3E%3C/mask%3E%3C/defs%3E%3Cg mask="url(#m)"%3E%3Cg fill="none" stroke="#7A5248" stroke-opacity=".34" stroke-linecap="round"%3E%3Cpath d="M-8 84C70 62 150 22 232 -4" stroke-width="3.2"/%3E%3Cpath d="M472 84C394 62 314 22 232 -4" stroke-width="2.6"/%3E%3Cpath d="M86 60C112 96 150 108 196 120" stroke-width="1.7"/%3E%3Cpath d="M372 52C360 92 336 112 300 138" stroke-width="1.5"/%3E%3Cpath d="M232 -4C252 26 268 44 296 58" stroke-width="1.5"/%3E%3C/g%3E%3Cuse href="#f" fill="#FFFFFF" stroke="#EBB3C1" stroke-width=".7" transform="translate(18 26) rotate(0) scale(1.52)"/%3E%3Cuse href="#f" fill="#FFFFFF" stroke="#EBB3C1" stroke-width=".7" transform="translate(498 26) rotate(0) scale(1.52)"/%3E%3Cuse href="#f" fill="#FFF3F6" stroke="#E9A9B9" stroke-width=".7" transform="translate(61 12) rotate(37) scale(1.33)"/%3E%3Cuse href="#f" fill="#FDDDE5" stroke="#E39BAD" stroke-width=".7" transform="translate(104 40) rotate(2) scale(1.18)"/%3E%3Cuse href="#f" fill="#F8C6D2" stroke="#D98CA0" stroke-width=".7" transform="translate(147 18) rotate(39) scale(1.46)"/%3E%3Cuse href="#f" fill="#FFFFFF" stroke="#EBB3C1" stroke-width=".7" transform="translate(192 33) rotate(4) scale(1.26)"/%3E%3Cuse href="#f" fill="#FFF3F6" stroke="#E9A9B9" stroke-width=".7" transform="translate(233 14) rotate(41) scale(1.55)"/%3E%3Cuse href="#f" fill="#FDDDE5" stroke="#E39BAD" stroke-width=".7" transform="translate(271 38) rotate(6) scale(1.21)"/%3E%3Cuse href="#f" fill="#F8C6D2" stroke="#D98CA0" stroke-width=".7" transform="translate(312 20) rotate(43) scale(1.40)"/%3E%3Cuse href="#f" fill="#FFFFFF" stroke="#EBB3C1" stroke-width=".7" transform="translate(352 30) rotate(8) scale(1.15)"/%3E%3Cuse href="#f" fill="#FFF3F6" stroke="#E9A9B9" stroke-width=".7" transform="translate(396 16) rotate(45) scale(1.49)"/%3E%3Cuse href="#f" fill="#FDDDE5" stroke="#E39BAD" stroke-width=".7" transform="translate(436 36) rotate(10) scale(1.24)"/%3E%3Cuse href="#f" fill="#F8C6D2" stroke="#D98CA0" stroke-width=".7" transform="translate(466 22) rotate(47) scale(1.31)"/%3E%3Cuse href="#f" fill="#F8C6D2" stroke="#D98CA0" stroke-width=".7" transform="translate(-14 22) rotate(47) scale(1.31)"/%3E%3Cuse href="#f" fill="#FFFFFF" stroke="#EBB3C1" stroke-width=".7" transform="translate(36 74) rotate(12) scale(1.08)"/%3E%3Cuse href="#f" fill="#FFFFFF" stroke="#EBB3C1" stroke-width=".7" transform="translate(516 74) rotate(12) scale(1.08)"/%3E%3Cuse href="#f" fill="#FFF3F6" stroke="#E9A9B9" stroke-width=".7" transform="translate(88 92) rotate(49) scale(1.22)"/%3E%3Cuse href="#f" fill="#FDDDE5" stroke="#E39BAD" stroke-width=".7" transform="translate(131 66) rotate(14) scale(0.96)"/%3E%3Cuse href="#f" fill="#F8C6D2" stroke="#D98CA0" stroke-width=".7" transform="translate(178 88) rotate(51) scale(1.12)"/%3E%3Cuse href="#f" fill="#FFFFFF" stroke="#EBB3C1" stroke-width=".7" transform="translate(216 70) rotate(16) scale(1.02)"/%3E%3Cuse href="#f" fill="#FFF3F6" stroke="#E9A9B9" stroke-width=".7" transform="translate(258 95) rotate(53) scale(1.18)"/%3E%3Cuse href="#f" fill="#FDDDE5" stroke="#E39BAD" stroke-width=".7" transform="translate(299 72) rotate(18) scale(0.92)"/%3E%3Cuse href="#f" fill="#F8C6D2" stroke="#D98CA0" stroke-width=".7" transform="translate(341 90) rotate(55) scale(1.06)"/%3E%3Cuse href="#f" fill="#FFFFFF" stroke="#EBB3C1" stroke-width=".7" transform="translate(382 68) rotate(20) scale(1.15)"/%3E%3Cuse href="#f" fill="#FFF3F6" stroke="#E9A9B9" stroke-width=".7" transform="translate(424 94) rotate(57) scale(0.98)"/%3E%3Cuse href="#f" fill="#FDDDE5" stroke="#E39BAD" stroke-width=".7" transform="translate(458 76) rotate(22) scale(1.10)"/%3E%3Cuse href="#f" fill="#FDDDE5" stroke="#E39BAD" stroke-width=".7" transform="translate(-22 76) rotate(22) scale(1.10)"/%3E%3Cuse href="#f" fill="#F8C6D2" stroke="#D98CA0" stroke-width=".7" transform="translate(24 132) rotate(59) scale(0.86)"/%3E%3Cuse href="#f" fill="#F8C6D2" stroke="#D98CA0" stroke-width=".7" transform="translate(504 132) rotate(59) scale(0.86)"/%3E%3Cuse href="#f" fill="#FFFFFF" stroke="#EBB3C1" stroke-width=".7" transform="translate(72 152) rotate(24) scale(0.74)"/%3E%3Cuse href="#f" fill="#FFF3F6" stroke="#E9A9B9" stroke-width=".7" transform="translate(118 128) rotate(61) scale(0.92)"/%3E%3Cuse href="#f" fill="#FDDDE5" stroke="#E39BAD" stroke-width=".7" transform="translate(165 148) rotate(26) scale(0.70)"/%3E%3Cuse href="#f" fill="#F8C6D2" stroke="#D98CA0" stroke-width=".7" transform="translate(205 134) rotate(63) scale(0.82)"/%3E%3Cuse href="#f" fill="#FFFFFF" stroke="#EBB3C1" stroke-width=".7" transform="translate(252 156) rotate(28) scale(0.66)"/%3E%3Cuse href="#f" fill="#FFF3F6" stroke="#E9A9B9" stroke-width=".7" transform="translate(294 130) rotate(65) scale(0.88)"/%3E%3Cuse href="#f" fill="#FDDDE5" stroke="#E39BAD" stroke-width=".7" transform="translate(336 150) rotate(30) scale(0.72)"/%3E%3Cuse href="#f" fill="#F8C6D2" stroke="#D98CA0" stroke-width=".7" transform="translate(378 136) rotate(67) scale(0.80)"/%3E%3Cuse href="#f" fill="#FFFFFF" stroke="#EBB3C1" stroke-width=".7" transform="translate(420 158) rotate(32) scale(0.64)"/%3E%3Cuse href="#f" fill="#FFF3F6" stroke="#E9A9B9" stroke-width=".7" transform="translate(462 140) rotate(69) scale(0.76)"/%3E%3Cuse href="#f" fill="#FFF3F6" stroke="#E9A9B9" stroke-width=".7" transform="translate(-18 140) rotate(69) scale(0.76)"/%3E%3Cuse href="#f" fill="#FDDDE5" stroke="#E39BAD" stroke-width=".7" transform="translate(46 196) rotate(34) scale(0.58)"/%3E%3Cuse href="#f" fill="#F8C6D2" stroke="#D98CA0" stroke-width=".7" transform="translate(140 208) rotate(71) scale(0.52)"/%3E%3Cuse href="#f" fill="#FFFFFF" stroke="#EBB3C1" stroke-width=".7" transform="translate(228 192) rotate(36) scale(0.60)"/%3E%3Cuse href="#f" fill="#FFF3F6" stroke="#E9A9B9" stroke-width=".7" transform="translate(318 206) rotate(1) scale(0.50)"/%3E%3Cuse href="#f" fill="#FDDDE5" stroke="#E39BAD" stroke-width=".7" transform="translate(404 198) rotate(38) scale(0.56)"/%3E%3C/g%3E%3C/svg%3E") and leave the paper alone, which is
     why oxblood still measures past 8:1 here instead of needing a rescue.

     Unlike Acid Garage this does not invert the ground, so the seven values
     that costume broke by being dark are not in play. What IS in play is
     everything that assumed a FLAT ground: the canopy is a picture behind
     the top of the page, and type over a picture is the new measurement. */
  :root[data-skin="sakura"] {
    --ink:      #4A2E2A;   /* cocoa, not black: the linework colour */
    --ink-rgb:  74,46,42;
    --plaster:  #F5F3F0;
    --card:     #FFFCF7;
    --tile:     #B44A6C;   /* rose — selection, Done, today */
    --tile-rgb: 180,74,108;
    --tile-soft:#F4A9BC;
    --tile-soft-rgb: 244,169,188;
    --tile-hover: #9C3D5C;
    /* --glaze has TWO jobs and they want opposite things, which is how the
       first pass here shipped a bug. It is a tint (the picker's band, a row
       hover, today's cell) AND it is a text colour on the cocoa nav — the
       undo toast is `background: var(--ink); color: var(--glaze)`. Setting it
       to an alpha for the masthead's sake left that toast at a third opacity
       on its own dark ground, which nothing on the Today screen would ever
       have shown. Solid, so both jobs work; the masthead veil is its own
       gradient below and borrows nothing. 11.6:1 as toast text. */
    --glaze:    #F6E9EC;
    --glaze-rgb: 246,233,236;
    /* Brass, and it stays brass in both houses — brand, not location. This
       is the trivial case Lisbon gets for free and Acid Garage had to earn
       by alternation, because neither house here is gold. */
    --latao:    #C9A15A;
    --rule:     rgba(74,46,42,.13);

    /* Reserved, and a hue apart. 8.2:1 and 7.0:1 on card. */
    --oxblood:  #8A2B3F;
    --ochre:    #7E5409;
    --sage:     #2F7F7A;

    /* Six types, and the pair that always gets closest — gold and
       terracotta — is pulled apart by sending the clay warmer. */
    --t-todo:   #D69A2D;
    --t-upkeep: #B9533C;
    --t-bill:   #2F7F7A;
    --t-meal:   #8A5A9C;
    --t-doc:    #4F73A8;
    --t-appt:   #3F7A4F;

    /* Blossom and leaf. SF takes the sky the canopy sits against;
       Guerneville takes hazakura — the green that comes in after the petals
       drop — which is the same joke the base palette makes with redwoods. */
    --sf:        #4E77A3;
    --sf-light:  #8FB0D0;
    --sf-wash:   rgba(78,119,163,.12);
    --sf-edge:   rgba(78,119,163,.40);
    --gv:        #3F7E5C;
    --gv-light:  #8CC0A4;
    --gv-wash:   rgba(63,126,92,.12);
    --gv-edge:   rgba(63,126,92,.40);
    --cell-sf:   rgba(78,119,163,.11);
    --cell-gv:   rgba(63,126,92,.11);
    --cell-today: rgba(180,74,108,.13);
    --today-line: #B44A6C;
    --bar-sf: #4E77A3;
    --bar-gv: #3F7E5C;
    --mk-ghost: rgba(var(--ink-rgb),.10);

    /* Rounded for everything that was serif or sans, mono left alone. One
       line, the same lever Acid Garage pulls with --serif: var(--mono) — and
       the whole of why this reads as soft rather than as Lisbon in pink.
       System rounded, so it costs no download: the mock asked for Nunito off
       Google Fonts and this app fetches nothing at runtime. */
    /* --ink-mute needs a nudge here and only here, and it is the ground that
       causes it rather than the costume being careless. Lisbon runs indigo on
       cream; this runs COCOA on a near-white, which is a lower-contrast pair
       to start from — so the base .68, commented "4.7:1 on card" over there,
       lands at 4.38 on plaster here. Under AA, on every frieze, group label
       and footer line in the app, before a single blossom is involved.

       .70 reads 4.65 on plaster and 4.87 on card. --ink-soft is already fine
       at 4.93 and is left alone: moving a token that passes would be solving
       a different number than the one that failed. */
    --ink-mute: rgba(var(--ink-rgb),.70);

    --rounded: ui-rounded, "SF Pro Rounded", "Hiragino Maru Gothic ProN", system-ui, sans-serif;
    --serif: var(--rounded);
    --ui: var(--rounded);

    /* No tile in the masthead; the canopy is on the page behind it. */
    --masthead-pattern: none;
    --band-pattern: none;
    --motif: none;
    /* A drifting petal beside a section label, in place of azulejo. */
    --frieze-pattern: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='17' height='13' viewBox='0 0 17 13'%3E%3Cg transform='translate(8.5 6.5) scale(.33)' fill='none' stroke='%23B44A6C' stroke-opacity='.5' stroke-width='3' stroke-linejoin='round'%3E%3Cpath id='p' d='M0 0C-6.5-4-7.5-12.5-4.2-17.5L0-15.2 4.2-17.5C7.5-12.5 6.5-4 0 0z'/%3E%3Cuse href='%23p' transform='rotate(72)'/%3E%3Cuse href='%23p' transform='rotate(144)'/%3E%3Cuse href='%23p' transform='rotate(216)'/%3E%3Cuse href='%23p' transform='rotate(288)'/%3E%3C/g%3E%3C/svg%3E");
    --scatter: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1200' height='1000' viewBox='0 0 1200 1000' xmlns:c2pa='http://c2pa.org/manifest'%3E%0A%3Cdefs%3E%0A%3Cg id='f'%3E%3Cg id='p'%3E%3Cpath d='M0 0C-6.5-4-7.5-12.5-4.2-17.5L0-15.2 4.2-17.5C7.5-12.5 6.5-4 0 0z'/%3E%3C/g%3E%3Cuse href='%23p' transform='rotate(72)'/%3E%3Cuse href='%23p' transform='rotate(144)'/%3E%3Cuse href='%23p' transform='rotate(216)'/%3E%3Cuse href='%23p' transform='rotate(288)'/%3E%3Ccircle r='3.4' fill='%23E88AA2' stroke='none'/%3E%3Cg fill='%23D9A23F' stroke='none'%3E%3Ccircle cy='-5.6' r='1'/%3E%3Ccircle cx='5.3' cy='-1.7' r='1'/%3E%3Ccircle cx='3.3' cy='4.5' r='1'/%3E%3Ccircle cx='-3.3' cy='4.5' r='1'/%3E%3Ccircle cx='-5.3' cy='-1.7' r='1'/%3E%3C/g%3E%3C/g%3E%0A%3Cpath id='l' d='M0 0C-4-3-4.5-8-2.5-11L0-9.6 2.5-11C4.5-8 4-3 0 0z'/%3E%0A%3C/defs%3E%0A%3Cg opacity='0.7'%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(76 220) rotate(127) scale(0.71)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(390 472) rotate(206) scale(0.71)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(93 189) rotate(332) scale(0.73)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(996 833) rotate(68) scale(0.76)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(342 725) rotate(100) scale(0.76)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(153 432) rotate(36) scale(0.77)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(1065 983) rotate(276) scale(0.77)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(904 306) rotate(85) scale(0.80)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(1076 122) rotate(302) scale(0.80)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(520 585) rotate(16) scale(0.82)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(43 796) rotate(85) scale(0.84)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(194 839) rotate(196) scale(0.85)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(596 728) rotate(252) scale(0.87)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(929 148) rotate(209) scale(0.88)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(418 68) rotate(312) scale(0.88)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(558 821) rotate(222) scale(0.89)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(1173 338) rotate(280) scale(0.89)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(296 263) rotate(246) scale(0.94)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(691 98) rotate(162) scale(0.94)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(946 434) rotate(297) scale(0.96)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(305 955) rotate(55) scale(0.99)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(806 632) rotate(225) scale(1.01)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(463 235) rotate(40) scale(1.01)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(695 955) rotate(166) scale(1.04)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(363 117) rotate(305) scale(1.04)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(672 557) rotate(182) scale(1.05)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(1190 459) rotate(180) scale(1.11)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(-10 459) rotate(180) scale(1.11)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(706 236) rotate(255) scale(1.13)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(653 796) rotate(150) scale(1.18)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(1031 677) rotate(244) scale(1.18)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(120 139) rotate(67) scale(0.52)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(535 469) rotate(6) scale(0.56)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(515 752) rotate(53) scale(0.62)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(174 906) rotate(26) scale(0.65)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(119 640) rotate(0) scale(0.67)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(444 264) rotate(11) scale(0.75)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(278 47) rotate(8) scale(0.77)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(894 151) rotate(45) scale(0.78)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(259 951) rotate(65) scale(0.78)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(1175 917) rotate(0) scale(0.81)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(-25 917) rotate(0) scale(0.81)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(346 679) rotate(1) scale(0.86)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(1175 97) rotate(53) scale(0.87)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(-25 97) rotate(53) scale(0.87)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(1087 750) rotate(47) scale(0.87)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(1026 518) rotate(69) scale(0.91)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(453 977) rotate(16) scale(1.00)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(453 -23) rotate(16) scale(1.00)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(878 557) rotate(10) scale(1.08)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(970 668) rotate(34) scale(1.08)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(667 285) rotate(48) scale(1.16)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(726 742) rotate(35) scale(1.17)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(1135 280) rotate(35) scale(1.18)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(649 499) rotate(70) scale(1.19)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(545 79) rotate(55) scale(1.26)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(955 359) rotate(46) scale(1.27)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(629 87) rotate(21) scale(1.28)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(849 941) rotate(5) scale(1.29)'/%3E%0A%3C/g%3E%0A%3C/svg%3E%0A");
  }

  /* THE CANOPY IS THREE LAYERS, and they are Jenn's: generated by
     `design/sakura/make_sakura.py`, documented in `docs/sakura-skin.md`, and
     shipped here as data URIs the way the tilework already is. The source
     files stay in `design/` like `assets-icon.svg` — what the browser loads
     is still four files and still offline.

     It is on `body` rather than the masthead because it is not a band: the
     masthead, the Front Door and the first card all sit IN it.

     Bottom to top: ground, sky wash, scatter, canopy. The canopy is a 960px
     tile repeating across, the scatter a 1200x1000 tile repeating in both
     directions, and the sky is a gradient so it scales on its own. Each tile
     draws anything crossing an edge again one width over, which is what
     makes the join invisible — the first scatter went in at 480x640 and
     visibly stamped every 480px on a monitor and never on the phone, which
     is the direction this project's bugs always run.

     `top center` on the canopy is what makes a phone show the MIDDLE of the
     tile, so a phone and a 27" monitor show the same tree rather than two
     different crops of it.

     THE SEASON IS THE HOUSE, and that is a better answer than tinting one
     picture: SF gets clouds and fog over blue, Guerneville gets young leaves
     over hazakura green — and the blossoms are in identical positions in
     both, because the generator draws them from their own random stream. So
     switching house changes the weather and not the tree. "You know which
     house you are in before you have read a word", carried by a picture.

     The C2PA manifest in each source file is stripped on the way in: it is
     provenance for a design file and 7.7 KB of base64 inside a background
     image. 89 KB of CSS, 8.9 KB over the wire. */
  :root[data-skin="sakura"] body,
  :root[data-skin="sakura"] .frontdoor {
    background-color: var(--plaster);
    background-image: var(--canopy), var(--scatter),
      linear-gradient(var(--sky-top), var(--sky-mid) 50%, rgba(245,243,240,0));
    background-repeat: repeat-x, repeat, no-repeat;
    background-size: 960px 340px, 1200px 1000px, 100% 310px;
    background-position: top center, 0 0, top left;
  }

  /* The sky is the one thing in the canopy that changes with the house, so
     the picture says where you are before a word is read — the rule a costume
     is not allowed to switch off. Blue over SF, hazakura green at
     Guerneville. */
  :root[data-skin="sakura"][data-house="sf"] {
    --sky-top: #B4D0EA; --sky-top-rgb: 180,208,234; --sky-mid: rgba(213,228,242,.85);
    --canopy: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='960' height='340' viewBox='0 0 960 340' xmlns:c2pa='http://c2pa.org/manifest'%3E%0A%3Cdefs%3E%0A%3Cg id='f'%3E%3Cg id='p'%3E%3Cpath d='M0 0C-6.5-4-7.5-12.5-4.2-17.5L0-15.2 4.2-17.5C7.5-12.5 6.5-4 0 0z'/%3E%3C/g%3E%3Cuse href='%23p' transform='rotate(72)'/%3E%3Cuse href='%23p' transform='rotate(144)'/%3E%3Cuse href='%23p' transform='rotate(216)'/%3E%3Cuse href='%23p' transform='rotate(288)'/%3E%3Ccircle r='3.4' fill='%23E88AA2' stroke='none'/%3E%3Cg fill='%23D9A23F' stroke='none'%3E%3Ccircle cy='-5.6' r='1'/%3E%3Ccircle cx='5.3' cy='-1.7' r='1'/%3E%3Ccircle cx='3.3' cy='4.5' r='1'/%3E%3Ccircle cx='-3.3' cy='4.5' r='1'/%3E%3Ccircle cx='-5.3' cy='-1.7' r='1'/%3E%3C/g%3E%3C/g%3E%0A%3Cpath id='l' d='M0 0C-4-3-4.5-8-2.5-11L0-9.6 2.5-11C4.5-8 4-3 0 0z'/%3E%0A%3Cg id='v'%3E%3Cpath d='M0 0C4.5-4 5.5-11 0-19C-5.5-11-4.5-4 0 0z'/%3E%3Cpath d='M0-1V-16' fill='none' stroke-opacity='.7'/%3E%3C/g%3E%0A%3Cg id='c'%3E%3Ccircle r='13'/%3E%3Ccircle cx='17' cy='-7' r='18'/%3E%3Ccircle cx='36' cy='-1' r='13'/%3E%3Ccircle cx='50' cy='5' r='9'/%3E%3Crect x='-10' width='68' height='14' rx='7'/%3E%3C/g%3E%0A%3ClinearGradient id='g' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%23fff'/%3E%3Cstop offset='.38' stop-color='%23fff'/%3E%3Cstop offset='1' stop-color='%23000'/%3E%3C/linearGradient%3E%0A%3Cmask id='m'%3E%3Crect width='960' height='340' fill='url(%23g)'/%3E%3C/mask%3E%0A%3Cfilter id='soft' x='-20%25' y='-50%25' width='140%25' height='200%25'%3E%3CfeGaussianBlur stdDeviation='1.2'/%3E%3C/filter%3E%0A%3Cfilter id='fog' x='-30%25' y='-300%25' width='160%25' height='700%25'%3E%3CfeGaussianBlur stdDeviation='9'/%3E%3C/filter%3E%0A%3C/defs%3E%0A%3Cg fill='%23fff' filter='url(%23soft)'%3E%0A%3Cuse href='%23c' transform='translate(144 210) scale(1.00)' fill-opacity='0.94'/%3E%0A%3Cuse href='%23c' transform='translate(451 211) scale(0.81)' fill-opacity='0.95'/%3E%0A%3Cuse href='%23c' transform='translate(760 192) scale(0.92)' fill-opacity='0.88'/%3E%0A%3C/g%3E%0A%3Cg mask='url(%23m)'%3E%0A%3Cg fill='none' stroke='%237A5248' stroke-opacity='.38' stroke-linecap='round'%3E%0A%3Cpath d='M79 -6C119 41 189 75 279 92' stroke-width='3'/%3E%0A%3Cpath d='M189 71C199 102 229 122 264 136' stroke-width='1.6'/%3E%0A%3Cpath d='M549 -6C589 41 659 75 749 92' stroke-width='3'/%3E%0A%3Cpath d='M659 71C669 102 699 122 734 136' stroke-width='1.6'/%3E%0A%3C/g%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(145 302) rotate(46) scale(0.39)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(894 241) rotate(19) scale(0.44)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(209 300) rotate(37) scale(0.46)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(703 136) rotate(17) scale(0.57)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(326 117) rotate(26) scale(0.57)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(98 143) rotate(25) scale(0.59)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(445 160) rotate(13) scale(0.59)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(289 59) rotate(35) scale(0.60)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(707 124) rotate(9) scale(0.60)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(142 119) rotate(38) scale(0.61)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(848 27) rotate(57) scale(0.62)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(90 101) rotate(60) scale(0.62)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(176 227) rotate(48) scale(0.63)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(890 57) rotate(21) scale(0.64)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(893 85) rotate(57) scale(0.64)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(869 158) rotate(60) scale(0.64)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(334 159) rotate(66) scale(0.66)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(748 19) rotate(16) scale(0.66)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(807 95) rotate(35) scale(0.68)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(746 54) rotate(16) scale(0.68)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(432 152) rotate(14) scale(0.68)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(268 50) rotate(31) scale(0.68)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(242 27) rotate(64) scale(0.68)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(543 8) rotate(7) scale(0.69)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(895 11) rotate(67) scale(0.70)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(41 126) rotate(64) scale(0.72)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(214 244) rotate(28) scale(0.72)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(259 138) rotate(63) scale(0.72)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(146 56) rotate(56) scale(0.73)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(157 166) rotate(48) scale(0.73)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(889 40) rotate(37) scale(0.73)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(667 205) rotate(58) scale(0.73)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(238 38) rotate(63) scale(0.74)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(898 171) rotate(34) scale(0.75)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(153 229) rotate(57) scale(0.77)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(223 62) rotate(1) scale(0.77)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(379 306) rotate(20) scale(0.77)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(895 47) rotate(67) scale(0.79)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(723 62) rotate(52) scale(0.79)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(678 87) rotate(43) scale(0.79)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(929 125) rotate(64) scale(0.80)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(-31 125) rotate(64) scale(0.80)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(497 77) rotate(3) scale(0.81)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(141 273) rotate(67) scale(0.81)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(501 1) rotate(58) scale(0.81)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(291 56) rotate(19) scale(0.81)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(914 60) rotate(62) scale(0.82)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(270 67) rotate(41) scale(0.83)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(258 12) rotate(33) scale(0.83)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(361 32) rotate(44) scale(0.84)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(83 35) rotate(8) scale(0.84)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(420 251) rotate(12) scale(0.84)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(919 82) rotate(33) scale(0.85)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(402 69) rotate(7) scale(0.85)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(243 150) rotate(59) scale(0.85)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(117 62) rotate(43) scale(0.86)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(191 28) rotate(51) scale(0.86)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(922 41) rotate(7) scale(0.87)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(644 97) rotate(9) scale(0.87)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(547 46) rotate(52) scale(0.88)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(281 36) rotate(41) scale(0.88)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(399 59) rotate(48) scale(0.88)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(883 121) rotate(41) scale(0.90)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(544 117) rotate(65) scale(0.90)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(347 78) rotate(65) scale(0.90)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(238 203) rotate(71) scale(0.90)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(630 21) rotate(61) scale(0.91)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(330 190) rotate(36) scale(0.91)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(874 184) rotate(18) scale(0.91)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(550 127) rotate(64) scale(0.91)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(342 142) rotate(46) scale(0.91)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(108 30) rotate(29) scale(0.92)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(86 11) rotate(5) scale(0.92)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(544 53) rotate(53) scale(0.92)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(617 40) rotate(33) scale(0.93)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(99 115) rotate(7) scale(0.93)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(17 142) rotate(66) scale(0.93)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(977 142) rotate(66) scale(0.93)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(494 198) rotate(41) scale(0.93)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(854 2) rotate(63) scale(0.93)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(114 28) rotate(24) scale(0.94)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(303 127) rotate(54) scale(0.95)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(776 53) rotate(46) scale(0.96)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(312 41) rotate(50) scale(0.96)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(106 118) rotate(13) scale(0.97)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(655 100) rotate(0) scale(0.97)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(302 102) rotate(46) scale(0.98)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(82 126) rotate(43) scale(1.00)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(861 39) rotate(52) scale(1.00)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(87 17) rotate(47) scale(1.00)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(595 75) rotate(68) scale(1.01)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(316 32) rotate(31) scale(1.01)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(789 22) rotate(11) scale(1.01)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(560 89) rotate(64) scale(1.03)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(519 56) rotate(71) scale(1.03)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(428 36) rotate(2) scale(1.04)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(594 145) rotate(68) scale(1.04)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(723 20) rotate(38) scale(1.05)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(163 221) rotate(3) scale(1.05)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(148 191) rotate(20) scale(1.05)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(850 41) rotate(48) scale(1.06)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(880 14) rotate(9) scale(1.06)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(358 136) rotate(25) scale(1.06)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(381 142) rotate(5) scale(1.06)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(330 73) rotate(32) scale(1.07)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(897 69) rotate(55) scale(1.07)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(835 1) rotate(46) scale(1.08)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(116 152) rotate(41) scale(1.08)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(288 0) rotate(10) scale(1.09)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(848 107) rotate(70) scale(1.09)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(877 153) rotate(10) scale(1.09)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(698 3) rotate(44) scale(1.09)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(361 2) rotate(8) scale(1.10)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(373 124) rotate(0) scale(1.10)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(896 87) rotate(24) scale(1.10)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(745 57) rotate(31) scale(1.10)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(357 0) rotate(9) scale(1.10)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(6 155) rotate(27) scale(1.12)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(966 155) rotate(27) scale(1.12)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(915 54) rotate(65) scale(1.15)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(128 108) rotate(7) scale(1.16)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(566 17) rotate(36) scale(1.16)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(474 98) rotate(36) scale(1.17)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(158 34) rotate(19) scale(1.17)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(61 58) rotate(50) scale(1.17)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(126 57) rotate(13) scale(1.17)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(403 131) rotate(29) scale(1.17)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(459 165) rotate(55) scale(1.18)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(171 6) rotate(2) scale(1.20)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(299 38) rotate(60) scale(1.20)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(89 195) rotate(49) scale(1.21)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(351 25) rotate(64) scale(1.21)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(425 242) rotate(0) scale(1.22)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(602 205) rotate(67) scale(1.22)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(313 27) rotate(13) scale(1.22)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(908 93) rotate(19) scale(1.24)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(60 157) rotate(8) scale(1.24)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(603 17) rotate(62) scale(1.25)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(429 108) rotate(17) scale(1.25)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(196 112) rotate(55) scale(1.26)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(631 118) rotate(41) scale(1.27)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(455 28) rotate(62) scale(1.28)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(609 188) rotate(3) scale(1.28)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(757 28) rotate(30) scale(1.29)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(31 104) rotate(47) scale(1.29)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(991 104) rotate(47) scale(1.29)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(766 158) rotate(50) scale(1.31)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(101 197) rotate(34) scale(1.31)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(921 28) rotate(57) scale(1.32)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(191 8) rotate(57) scale(1.32)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(456 156) rotate(70) scale(1.32)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(492 17) rotate(14) scale(1.32)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(234 61) rotate(67) scale(1.32)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(929 124) rotate(34) scale(1.33)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(-31 124) rotate(34) scale(1.33)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(292 28) rotate(32) scale(1.33)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(474 71) rotate(18) scale(1.33)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(528 118) rotate(42) scale(1.33)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(319 105) rotate(59) scale(1.33)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(349 194) rotate(50) scale(1.34)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(930 170) rotate(6) scale(1.34)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(-30 170) rotate(6) scale(1.34)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(524 23) rotate(64) scale(1.35)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(772 82) rotate(0) scale(1.35)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(52 152) rotate(18) scale(1.36)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(408 33) rotate(34) scale(1.36)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(888 18) rotate(63) scale(1.37)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(186 75) rotate(28) scale(1.37)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(662 61) rotate(38) scale(1.38)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(390 96) rotate(58) scale(1.38)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(852 39) rotate(2) scale(1.38)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(546 58) rotate(29) scale(1.39)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(125 68) rotate(70) scale(1.39)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(759 167) rotate(33) scale(1.39)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(274 27) rotate(59) scale(1.40)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(222 47) rotate(63) scale(1.41)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(877 31) rotate(41) scale(1.42)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(330 110) rotate(15) scale(1.44)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(127 61) rotate(23) scale(1.45)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(297 13) rotate(36) scale(1.45)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(74 68) rotate(5) scale(1.47)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(644 79) rotate(31) scale(1.47)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(459 5) rotate(66) scale(1.47)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(144 25) rotate(60) scale(1.48)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(710 22) rotate(26) scale(1.51)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(173 21) rotate(47) scale(1.53)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(35 93) rotate(64) scale(1.57)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(103 4) rotate(49) scale(1.57)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(894 89) rotate(24) scale(1.58)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(943 73) rotate(1) scale(1.61)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(-17 73) rotate(1) scale(1.61)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(61 25) rotate(64) scale(1.61)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(641 71) rotate(6) scale(1.61)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(725 41) rotate(35) scale(1.61)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(586 67) rotate(61) scale(1.61)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(194 10) rotate(17) scale(1.64)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(432 60) rotate(70) scale(1.64)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(405 28) rotate(71) scale(1.65)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(401 50) rotate(16) scale(1.66)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(357 17) rotate(57) scale(1.67)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(609 21) rotate(10) scale(1.67)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(629 3) rotate(58) scale(1.72)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(254 12) rotate(26) scale(1.74)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(122 309) rotate(161) scale(0.73)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(889 177) rotate(327) scale(1.09)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(213 181) rotate(242) scale(0.79)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(209 180) rotate(196) scale(0.88)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(143 316) rotate(21) scale(1.14)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(809 245) rotate(60) scale(0.89)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(438 287) rotate(332) scale(0.91)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(559 186) rotate(228) scale(0.95)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(172 86) rotate(238) scale(0.82)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(733 271) rotate(91) scale(1.11)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(384 101) rotate(220) scale(0.88)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(770 205) rotate(20) scale(1.02)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(79 260) rotate(27) scale(1.08)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(859 240) rotate(13) scale(1.13)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(956 259) rotate(99) scale(0.77)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(-4 259) rotate(99) scale(0.77)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(850 154) rotate(351) scale(1.09)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(893 101) rotate(312) scale(1.08)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(152 298) rotate(233) scale(0.77)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(482 304) rotate(303) scale(0.83)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(486 161) rotate(101) scale(0.79)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(155 308) rotate(192) scale(0.78)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(753 112) rotate(325) scale(1.13)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(928 193) rotate(129) scale(1.20)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(605 179) rotate(135) scale(0.89)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(354 120) rotate(41) scale(0.92)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(170 262) rotate(151) scale(1.11)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(244 237) rotate(0) scale(1.07)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(213 154) rotate(213) scale(0.96)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(860 116) rotate(313) scale(1.03)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(21 86) rotate(155) scale(0.75)'/%3E%0A%3Cg fill='%23fff' filter='url(%23fog)'%3E%0A%3Cellipse cx='144' cy='178' rx='160' ry='13' fill-opacity='0.8'/%3E%0A%3Cellipse cx='1104' cy='178' rx='160' ry='13' fill-opacity='0.8'/%3E%0A%3Cellipse cx='480' cy='232' rx='130' ry='10' fill-opacity='0.7'/%3E%0A%3Cellipse cx='768' cy='190' rx='150' ry='12' fill-opacity='0.75'/%3E%0A%3C/g%3E%0A%3C/g%3E%3C/svg%3E%0A");
  }
  :root[data-skin="sakura"][data-house="gv"] {
    --sky-top: #C3DFBD; --sky-top-rgb: 195,223,189; --sky-mid: rgba(221,235,214,.85);
    --canopy: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='960' height='340' viewBox='0 0 960 340' xmlns:c2pa='http://c2pa.org/manifest'%3E%0A%3Cdefs%3E%0A%3Cg id='f'%3E%3Cg id='p'%3E%3Cpath d='M0 0C-6.5-4-7.5-12.5-4.2-17.5L0-15.2 4.2-17.5C7.5-12.5 6.5-4 0 0z'/%3E%3C/g%3E%3Cuse href='%23p' transform='rotate(72)'/%3E%3Cuse href='%23p' transform='rotate(144)'/%3E%3Cuse href='%23p' transform='rotate(216)'/%3E%3Cuse href='%23p' transform='rotate(288)'/%3E%3Ccircle r='3.4' fill='%23E88AA2' stroke='none'/%3E%3Cg fill='%23D9A23F' stroke='none'%3E%3Ccircle cy='-5.6' r='1'/%3E%3Ccircle cx='5.3' cy='-1.7' r='1'/%3E%3Ccircle cx='3.3' cy='4.5' r='1'/%3E%3Ccircle cx='-3.3' cy='4.5' r='1'/%3E%3Ccircle cx='-5.3' cy='-1.7' r='1'/%3E%3C/g%3E%3C/g%3E%0A%3Cpath id='l' d='M0 0C-4-3-4.5-8-2.5-11L0-9.6 2.5-11C4.5-8 4-3 0 0z'/%3E%0A%3Cg id='v'%3E%3Cpath d='M0 0C4.5-4 5.5-11 0-19C-5.5-11-4.5-4 0 0z'/%3E%3Cpath d='M0-1V-16' fill='none' stroke-opacity='.7'/%3E%3C/g%3E%0A%3Cg id='c'%3E%3Ccircle r='13'/%3E%3Ccircle cx='17' cy='-7' r='18'/%3E%3Ccircle cx='36' cy='-1' r='13'/%3E%3Ccircle cx='50' cy='5' r='9'/%3E%3Crect x='-10' width='68' height='14' rx='7'/%3E%3C/g%3E%0A%3ClinearGradient id='g' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%23fff'/%3E%3Cstop offset='.38' stop-color='%23fff'/%3E%3Cstop offset='1' stop-color='%23000'/%3E%3C/linearGradient%3E%0A%3Cmask id='m'%3E%3Crect width='960' height='340' fill='url(%23g)'/%3E%3C/mask%3E%0A%3Cfilter id='soft' x='-20%25' y='-50%25' width='140%25' height='200%25'%3E%3CfeGaussianBlur stdDeviation='1.2'/%3E%3C/filter%3E%0A%3Cfilter id='fog' x='-30%25' y='-300%25' width='160%25' height='700%25'%3E%3CfeGaussianBlur stdDeviation='9'/%3E%3C/filter%3E%0A%3C/defs%3E%0A%3Cg mask='url(%23m)'%3E%0A%3Cg fill='none' stroke='%237A5248' stroke-opacity='.38' stroke-linecap='round'%3E%0A%3Cpath d='M79 -6C119 41 189 75 279 92' stroke-width='3'/%3E%0A%3Cpath d='M189 71C199 102 229 122 264 136' stroke-width='1.6'/%3E%0A%3Cpath d='M549 -6C589 41 659 75 749 92' stroke-width='3'/%3E%0A%3Cpath d='M659 71C669 102 699 122 734 136' stroke-width='1.6'/%3E%0A%3C/g%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(570 105) rotate(90) scale(0.75)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(866 73) rotate(17) scale(0.88)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(856 117) rotate(331) scale(0.88)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(11 32) rotate(227) scale(0.68)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(971 32) rotate(227) scale(0.68)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(878 175) rotate(94) scale(1.22)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(461 135) rotate(121) scale(0.65)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(591 51) rotate(111) scale(1.18)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(617 14) rotate(30) scale(0.95)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(274 30) rotate(302) scale(1.14)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(934 185) rotate(264) scale(0.91)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(94 159) rotate(225) scale(0.91)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(720 46) rotate(66) scale(0.87)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(543 129) rotate(247) scale(1.16)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(232 43) rotate(27) scale(0.71)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(320 3) rotate(234) scale(0.63)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(420 78) rotate(161) scale(0.65)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(159 42) rotate(171) scale(0.64)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(882 28) rotate(333) scale(0.61)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(623 74) rotate(312) scale(0.94)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(588 75) rotate(9) scale(1.00)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(806 46) rotate(123) scale(0.75)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(467 168) rotate(245) scale(1.08)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(786 55) rotate(20) scale(1.13)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(629 26) rotate(44) scale(0.96)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(77 187) rotate(231) scale(1.24)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(171 11) rotate(254) scale(0.85)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(422 13) rotate(123) scale(1.13)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(699 13) rotate(191) scale(1.09)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(497 42) rotate(65) scale(0.82)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(613 182) rotate(359) scale(0.85)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(446 51) rotate(351) scale(1.21)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(249 98) rotate(248) scale(0.99)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(562 18) rotate(69) scale(0.79)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(195 64) rotate(18) scale(1.07)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(615 28) rotate(46) scale(1.17)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(884 109) rotate(324) scale(0.73)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(893 27) rotate(62) scale(1.05)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(108 74) rotate(94) scale(0.77)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(711 26) rotate(276) scale(0.70)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(761 125) rotate(46) scale(1.24)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(581 124) rotate(219) scale(0.65)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(518 19) rotate(256) scale(0.80)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(837 16) rotate(87) scale(0.78)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(618 196) rotate(212) scale(0.87)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(414 133) rotate(312) scale(0.68)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(3 31) rotate(39) scale(1.21)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(963 31) rotate(39) scale(1.21)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(261 150) rotate(3) scale(1.16)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(145 302) rotate(46) scale(0.39)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(894 241) rotate(19) scale(0.44)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(209 300) rotate(37) scale(0.46)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(703 136) rotate(17) scale(0.57)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(326 117) rotate(26) scale(0.57)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(98 143) rotate(25) scale(0.59)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(445 160) rotate(13) scale(0.59)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(289 59) rotate(35) scale(0.60)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(707 124) rotate(9) scale(0.60)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(142 119) rotate(38) scale(0.61)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(848 27) rotate(57) scale(0.62)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(90 101) rotate(60) scale(0.62)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(176 227) rotate(48) scale(0.63)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(890 57) rotate(21) scale(0.64)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(893 85) rotate(57) scale(0.64)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(869 158) rotate(60) scale(0.64)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(334 159) rotate(66) scale(0.66)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(748 19) rotate(16) scale(0.66)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(807 95) rotate(35) scale(0.68)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(746 54) rotate(16) scale(0.68)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(432 152) rotate(14) scale(0.68)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(268 50) rotate(31) scale(0.68)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(242 27) rotate(64) scale(0.68)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(543 8) rotate(7) scale(0.69)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(895 11) rotate(67) scale(0.70)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(41 126) rotate(64) scale(0.72)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(214 244) rotate(28) scale(0.72)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(259 138) rotate(63) scale(0.72)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(146 56) rotate(56) scale(0.73)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(157 166) rotate(48) scale(0.73)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(889 40) rotate(37) scale(0.73)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(667 205) rotate(58) scale(0.73)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(238 38) rotate(63) scale(0.74)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(898 171) rotate(34) scale(0.75)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(153 229) rotate(57) scale(0.77)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(223 62) rotate(1) scale(0.77)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(379 306) rotate(20) scale(0.77)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(895 47) rotate(67) scale(0.79)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(723 62) rotate(52) scale(0.79)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(678 87) rotate(43) scale(0.79)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(929 125) rotate(64) scale(0.80)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(-31 125) rotate(64) scale(0.80)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(497 77) rotate(3) scale(0.81)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(141 273) rotate(67) scale(0.81)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(501 1) rotate(58) scale(0.81)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(291 56) rotate(19) scale(0.81)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(914 60) rotate(62) scale(0.82)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(270 67) rotate(41) scale(0.83)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(258 12) rotate(33) scale(0.83)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(361 32) rotate(44) scale(0.84)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(83 35) rotate(8) scale(0.84)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(420 251) rotate(12) scale(0.84)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(919 82) rotate(33) scale(0.85)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(402 69) rotate(7) scale(0.85)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(243 150) rotate(59) scale(0.85)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(117 62) rotate(43) scale(0.86)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(191 28) rotate(51) scale(0.86)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(922 41) rotate(7) scale(0.87)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(644 97) rotate(9) scale(0.87)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(547 46) rotate(52) scale(0.88)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(281 36) rotate(41) scale(0.88)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(399 59) rotate(48) scale(0.88)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(883 121) rotate(41) scale(0.90)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(544 117) rotate(65) scale(0.90)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(347 78) rotate(65) scale(0.90)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(238 203) rotate(71) scale(0.90)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(630 21) rotate(61) scale(0.91)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(330 190) rotate(36) scale(0.91)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(874 184) rotate(18) scale(0.91)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(550 127) rotate(64) scale(0.91)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(342 142) rotate(46) scale(0.91)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(108 30) rotate(29) scale(0.92)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(86 11) rotate(5) scale(0.92)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(544 53) rotate(53) scale(0.92)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(617 40) rotate(33) scale(0.93)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(99 115) rotate(7) scale(0.93)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(17 142) rotate(66) scale(0.93)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(977 142) rotate(66) scale(0.93)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(494 198) rotate(41) scale(0.93)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(854 2) rotate(63) scale(0.93)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(114 28) rotate(24) scale(0.94)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(303 127) rotate(54) scale(0.95)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(776 53) rotate(46) scale(0.96)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(312 41) rotate(50) scale(0.96)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(106 118) rotate(13) scale(0.97)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(655 100) rotate(0) scale(0.97)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(302 102) rotate(46) scale(0.98)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(82 126) rotate(43) scale(1.00)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(861 39) rotate(52) scale(1.00)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(87 17) rotate(47) scale(1.00)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(595 75) rotate(68) scale(1.01)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(316 32) rotate(31) scale(1.01)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(789 22) rotate(11) scale(1.01)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(560 89) rotate(64) scale(1.03)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(519 56) rotate(71) scale(1.03)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(428 36) rotate(2) scale(1.04)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(594 145) rotate(68) scale(1.04)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(723 20) rotate(38) scale(1.05)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(163 221) rotate(3) scale(1.05)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(148 191) rotate(20) scale(1.05)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(850 41) rotate(48) scale(1.06)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(880 14) rotate(9) scale(1.06)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(358 136) rotate(25) scale(1.06)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(381 142) rotate(5) scale(1.06)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(330 73) rotate(32) scale(1.07)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(897 69) rotate(55) scale(1.07)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(835 1) rotate(46) scale(1.08)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(116 152) rotate(41) scale(1.08)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(288 0) rotate(10) scale(1.09)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(848 107) rotate(70) scale(1.09)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(877 153) rotate(10) scale(1.09)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(698 3) rotate(44) scale(1.09)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(361 2) rotate(8) scale(1.10)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(373 124) rotate(0) scale(1.10)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(896 87) rotate(24) scale(1.10)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(745 57) rotate(31) scale(1.10)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(357 0) rotate(9) scale(1.10)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(6 155) rotate(27) scale(1.12)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(966 155) rotate(27) scale(1.12)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(915 54) rotate(65) scale(1.15)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(128 108) rotate(7) scale(1.16)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(566 17) rotate(36) scale(1.16)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(474 98) rotate(36) scale(1.17)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(158 34) rotate(19) scale(1.17)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(61 58) rotate(50) scale(1.17)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(126 57) rotate(13) scale(1.17)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(403 131) rotate(29) scale(1.17)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(459 165) rotate(55) scale(1.18)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(171 6) rotate(2) scale(1.20)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(299 38) rotate(60) scale(1.20)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(89 195) rotate(49) scale(1.21)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(351 25) rotate(64) scale(1.21)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(425 242) rotate(0) scale(1.22)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(602 205) rotate(67) scale(1.22)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(313 27) rotate(13) scale(1.22)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(908 93) rotate(19) scale(1.24)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(60 157) rotate(8) scale(1.24)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(603 17) rotate(62) scale(1.25)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(429 108) rotate(17) scale(1.25)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(196 112) rotate(55) scale(1.26)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(631 118) rotate(41) scale(1.27)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(455 28) rotate(62) scale(1.28)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(609 188) rotate(3) scale(1.28)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(757 28) rotate(30) scale(1.29)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(31 104) rotate(47) scale(1.29)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(991 104) rotate(47) scale(1.29)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(766 158) rotate(50) scale(1.31)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(101 197) rotate(34) scale(1.31)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(921 28) rotate(57) scale(1.32)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(191 8) rotate(57) scale(1.32)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(456 156) rotate(70) scale(1.32)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(492 17) rotate(14) scale(1.32)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(234 61) rotate(67) scale(1.32)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(929 124) rotate(34) scale(1.33)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(-31 124) rotate(34) scale(1.33)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(292 28) rotate(32) scale(1.33)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(474 71) rotate(18) scale(1.33)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(528 118) rotate(42) scale(1.33)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(319 105) rotate(59) scale(1.33)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(349 194) rotate(50) scale(1.34)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(930 170) rotate(6) scale(1.34)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(-30 170) rotate(6) scale(1.34)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(524 23) rotate(64) scale(1.35)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(772 82) rotate(0) scale(1.35)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(52 152) rotate(18) scale(1.36)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(408 33) rotate(34) scale(1.36)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(888 18) rotate(63) scale(1.37)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(186 75) rotate(28) scale(1.37)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(662 61) rotate(38) scale(1.38)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(390 96) rotate(58) scale(1.38)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(852 39) rotate(2) scale(1.38)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(546 58) rotate(29) scale(1.39)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(125 68) rotate(70) scale(1.39)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(759 167) rotate(33) scale(1.39)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(274 27) rotate(59) scale(1.40)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(222 47) rotate(63) scale(1.41)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(877 31) rotate(41) scale(1.42)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(330 110) rotate(15) scale(1.44)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(127 61) rotate(23) scale(1.45)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(297 13) rotate(36) scale(1.45)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(74 68) rotate(5) scale(1.47)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(644 79) rotate(31) scale(1.47)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(459 5) rotate(66) scale(1.47)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(144 25) rotate(60) scale(1.48)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(710 22) rotate(26) scale(1.51)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(173 21) rotate(47) scale(1.53)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(35 93) rotate(64) scale(1.57)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(103 4) rotate(49) scale(1.57)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(894 89) rotate(24) scale(1.58)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(943 73) rotate(1) scale(1.61)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(-17 73) rotate(1) scale(1.61)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(61 25) rotate(64) scale(1.61)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(641 71) rotate(6) scale(1.61)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(725 41) rotate(35) scale(1.61)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(586 67) rotate(61) scale(1.61)'/%3E%0A%3Cuse href='%23f' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.7' transform='translate(194 10) rotate(17) scale(1.64)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(432 60) rotate(70) scale(1.64)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(405 28) rotate(71) scale(1.65)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(401 50) rotate(16) scale(1.66)'/%3E%0A%3Cuse href='%23f' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.7' transform='translate(357 17) rotate(57) scale(1.67)'/%3E%0A%3Cuse href='%23f' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.7' transform='translate(609 21) rotate(10) scale(1.67)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(629 3) rotate(58) scale(1.72)'/%3E%0A%3Cuse href='%23f' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.7' transform='translate(254 12) rotate(26) scale(1.74)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(937 134) rotate(100) scale(0.96)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(-23 134) rotate(100) scale(0.96)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(181 26) rotate(36) scale(0.68)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(278 67) rotate(13) scale(0.82)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(378 63) rotate(136) scale(1.15)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(19 172) rotate(232) scale(1.00)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(979 172) rotate(232) scale(1.00)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(306 98) rotate(88) scale(0.94)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(540 51) rotate(350) scale(0.77)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(448 82) rotate(160) scale(0.90)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(806 129) rotate(277) scale(0.92)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(177 32) rotate(11) scale(1.11)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(250 44) rotate(200) scale(0.79)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(821 24) rotate(61) scale(0.96)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(191 16) rotate(145) scale(0.85)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(946 24) rotate(7) scale(1.21)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(-14 24) rotate(7) scale(1.21)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(196 123) rotate(184) scale(1.00)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(65 20) rotate(93) scale(1.11)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(245 67) rotate(270) scale(0.60)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(65 34) rotate(262) scale(1.13)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(356 128) rotate(254) scale(0.86)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(267 59) rotate(137) scale(0.61)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(452 124) rotate(336) scale(0.62)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(795 218) rotate(138) scale(1.15)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(86 14) rotate(272) scale(0.84)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(290 141) rotate(22) scale(0.90)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(468 3) rotate(189) scale(0.75)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(647 32) rotate(291) scale(0.97)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(658 2) rotate(36) scale(0.99)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(762 154) rotate(86) scale(0.94)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(890 55) rotate(224) scale(0.82)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(791 26) rotate(340) scale(0.64)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(932 72) rotate(82) scale(0.74)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(615 26) rotate(207) scale(0.68)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(744 50) rotate(282) scale(1.09)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(672 27) rotate(317) scale(1.08)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(912 38) rotate(204) scale(0.83)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(866 39) rotate(129) scale(0.72)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(720 45) rotate(285) scale(1.13)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(180 110) rotate(43) scale(1.05)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(577 70) rotate(140) scale(1.00)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(513 138) rotate(137) scale(1.05)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(186 115) rotate(305) scale(0.67)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(698 26) rotate(252) scale(0.62)'/%3E%0A%3Cuse href='%23v' fill='%237FB57C' stroke='%234F7F50' stroke-width='0.7' transform='translate(870 117) rotate(27) scale(0.76)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(497 91) rotate(19) scale(0.84)'/%3E%0A%3Cuse href='%23v' fill='%23B5DAA0' stroke='%236A9A63' stroke-width='0.7' transform='translate(525 15) rotate(150) scale(0.80)'/%3E%0A%3Cuse href='%23v' fill='%239CCB8E' stroke='%235E8F5C' stroke-width='0.7' transform='translate(543 179) rotate(28) scale(0.63)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(122 309) rotate(161) scale(0.73)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(889 177) rotate(327) scale(1.09)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(213 181) rotate(242) scale(0.79)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(209 180) rotate(196) scale(0.88)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(143 316) rotate(21) scale(1.14)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(809 245) rotate(60) scale(0.89)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(438 287) rotate(332) scale(0.91)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(559 186) rotate(228) scale(0.95)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(172 86) rotate(238) scale(0.82)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(733 271) rotate(91) scale(1.11)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(384 101) rotate(220) scale(0.88)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(770 205) rotate(20) scale(1.02)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(79 260) rotate(27) scale(1.08)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(859 240) rotate(13) scale(1.13)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(956 259) rotate(99) scale(0.77)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(-4 259) rotate(99) scale(0.77)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(850 154) rotate(351) scale(1.09)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(893 101) rotate(312) scale(1.08)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(152 298) rotate(233) scale(0.77)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(482 304) rotate(303) scale(0.83)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(486 161) rotate(101) scale(0.79)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(155 308) rotate(192) scale(0.78)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(753 112) rotate(325) scale(1.13)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(928 193) rotate(129) scale(1.20)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(605 179) rotate(135) scale(0.89)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(354 120) rotate(41) scale(0.92)'/%3E%0A%3Cuse href='%23l' fill='%23FFFFFF' stroke='%23EBB3C1' stroke-width='0.6' transform='translate(170 262) rotate(151) scale(1.11)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(244 237) rotate(0) scale(1.07)'/%3E%0A%3Cuse href='%23l' fill='%23F8C6D2' stroke='%23D98CA0' stroke-width='0.6' transform='translate(213 154) rotate(213) scale(0.96)'/%3E%0A%3Cuse href='%23l' fill='%23FFF3F6' stroke='%23E9A9B9' stroke-width='0.6' transform='translate(860 116) rotate(313) scale(1.03)'/%3E%0A%3Cuse href='%23l' fill='%23FDDDE5' stroke='%23E39BAD' stroke-width='0.6' transform='translate(21 86) rotate(155) scale(0.75)'/%3E%0A%3C/g%3E%3C/svg%3E%0A");
  }

  /* The short list gets its frame back, and it is a RESTORATION rather than a
     new idea. Lisbon's short list wore a --dest frame and gave it up when the
     motif came off the ground: "on plain plaster it was simply the loudest
     thing on the screen". The canopy puts the ground back, so the frame is
     earned again by exactly the condition that earned it the first time.

     var(--dest) rather than the hex, which was Jenn's correction and the
     right one: it is the destination's own colour doing wayfinding, not the
     reserved ochre doing decoration. Those are two different golds and the
     mock already separated them — --ochre #7E5409 stays free to mean "due
     soon" on the dates inside the card.

     IT GOES ON `.shortlist`, NOT `.shortlist-inner`, and that distinction is
     visible. The inner is where Lisbon's old frame lived, so the restoration
     went there by habit — but the inner has square corners and sits inside a
     parent with a 17px radius and `overflow: hidden`, which clips the
     border's corners off and leaves four blunt stops. Jenn caught it in a
     screenshot. `.shortlist` is the element that already owns the radius,
     the background and the shadow, so the border belongs to it; both are
     border-box and the same box, so moving it costs nothing in layout. */
  :root[data-skin="sakura"] .shortlist {
    border: 1.5px solid var(--dest, var(--tile));
  }

  /* THE GREETING IS THE ONLY BODY TEXT IN THIS APP THAT SITS ON A PICTURE,
     and it is the one thing the canopy broke. Measured against the worst
     pixel behind it — a branch stroke over sky, not the average — --ink-soft
     at .72 reads 3.10:1 in SF and 3.27 at Guerneville, under the 4.5 a body
     line needs. The date is fine at 4.97 and always was: it is 30px, where
     the floor is 3:1. Type over a picture is measured against the worst
     case, because the worst case is a real pixel and the average is not.

     The mock's answer was three stacked text-shadow glows, which make a line
     LOOK legible without moving the number at all — this file measures, so
     that is a fix that cannot be checked. Two that can: the masthead's own
     wash, now a plaster mist rather than a blue tint (and the mock already
     had fog as a motif, so it costs nothing thematically), and Jenn's own
     .85 on the greeting, which her artboard had and the base does not.

     Together: 4.92 SF, 5.12 Guerneville. The veil alone tops out at 4.41
     even at .70 opacity, by which point there is no canopy left to see.

     .85 became .90 once the canopy was allowed to reach the top of the
     screen: the greeting then sits on the densest part of the tile, and
     Guerneville notched came out at 4.17. The alternative was a heavier
     mist, and the whole point of that change was to SEE the blossoms — so
     the text darkens rather than the picture fading, which is the same
     trade `.on-ground` makes everywhere else in this skin. .90 reads 4.59
     in the worst of the four cases and leaves the mist where it was. */
  :root[data-skin="sakura"] .hello {
    color: rgba(var(--ink-rgb),.90);
  }

  /* NO BAND AND NO RULE UNDER THE MASTHEAD. Jenn's report, and her mocks
     never had either: the header sits IN the canopy and the picture runs on
     behind the cards. What was there was Lisbon's structure showing through
     — a tinted strip plus the 2px brass hairline — and against a photograph
     of a tree both read as a seam ruled across it.

     The mist cannot simply go, because it is what carries the greeting from
     3.72 to 4.79 against a blossom centre. So it becomes a GRADIENT instead
     of a band: full strength through the text, gone by the bottom edge. Same
     protection where the number is taken, no line anywhere.

     The brass goes with it, and that is a costume's call to make rather than
     drift — Acid Garage moved the same hairline to bracket the app top and
     bottom. Here it survives on the Front Door as the short rule under the
     wordmark, which is where Jenn's mock keeps it: an accent, not a divider. */
  /* THE STATUS CAP TAKES THE SKY, so the canopy reaches the top edge. It is
     --tile everywhere else, which re-houses correctly and knows nothing
     about a sky — on a notched phone that put a solid rose band across the
     top and cut the tree off below it. Jenn's screenshot is the only way
     this was ever going to show: the safe-area inset is 0 in a browser and
     on the Mac, so every check up to here had nothing to draw.

     Per house, because the sky is. Acid Garage made the same move for the
     opposite reason — there the cap had to stop being --tile because iOS
     draws the clock WHITE over this strip and violet is a mid-tone. That
     risk is the one to watch here too, since a light sky under white
     numerals would be worse than the rose was; Jenn's phone is drawing them
     dark, which is what makes this safe rather than merely prettier. */
  /* THE CAP SHOWS THE CANOPY, so the tree reaches the top of the screen.
     Jenn: "why can't the sakura blossom header continue to the top of the
     screen?" — and the answer was a rule that had gone out of date. The cap
     exists because `black-translucent` was documented as making iOS draw the
     clock in WHITE, which needs something dark beneath it. Her phone draws
     it BLACK, adapting to what is under it, which her own screenshots show
     twice over. Against the canopy's top band black measures 8.08:1.

     So it paints the same stack as `body`, at the same size and position.
     Both start at y=0 and span the viewport, so at the top of the page they
     line up exactly and there is no cap to see. What is left of its job is
     the one that still matters: it is opaque and above everything, so
     scrolled content passes behind a band of blossoms instead of behind the
     clock.

     It diverges while scrolling, because a fixed element cannot follow a
     scrolling background. That is the trade for having the tree reach the
     top, and it reads as a header strip rather than as a seam.

     WHITE STATUS TEXT WOULD BE UNREADABLE HERE — 1:1 on the pale blossoms.
     This rides on a device that draws it dark, which is verified for Jenn's
     phone and is the whole reason this is a costume rather than the base. */
  :root[data-skin="sakura"] .status-cap {
    background-color: var(--plaster);
    background-image: var(--canopy), var(--scatter),
      linear-gradient(var(--sky-top), var(--sky-mid) 50%, rgba(245,243,240,0));
    background-repeat: repeat-x, repeat, no-repeat;
    background-size: 960px 340px, 1200px 1000px, 100% 310px;
    background-position: top center, 0 0, top left;
  }

  :root[data-skin="sakura"] .masthead { background: transparent; }

  /* THE FRONT DOOR NEEDS THE CANOPY OF ITS OWN, because it is
     `position: fixed; inset: 0` over an opaque plaster — it covers the body
     and everything painted on it. Without this the one screen the costume
     most wants to land on was a flat pink page with a pale block at the top.
     Same four lines as `body`, written once for both: the stack is long
     enough that two copies would drift the first time either is touched.

     The band loses its PAINT and keeps its BOX, and that distinction cost a
     bug. `.frontdoor::before` is 190px of --glaze and --masthead-pattern
     masked into a fade — Lisbon's azulejo arriving once on the way in. Here
     the canopy is already that, so the paint would be a second fade over the
     first. But `.fd-in` is pulled up 86px to sit the wordmark INSIDE that
     band, and `display: none` took the 190px away while leaving the pull —
     so the wordmark and the date rendered at y -86 and -12, off the top of
     the screen, with scrollTop sitting at 0 and nothing to scroll to.

     Removing a box that something else is positioned against is the whole
     lesson. `background: none` keeps the spacer, keeps the arithmetic in
     `.fd-in` honest, and lets the canopy through. */
  :root[data-skin="sakura"] .frontdoor::before {
    background: none;
    background-image: none;
  }

  /* The door's own mist, and it is a SEPARATE box from the band above because
     the band cannot be moved. The wordmark is --tile rose at 36px sitting on
     blossom: 2.0:1 against the darkest pixel behind it, where large text needs
     3:1. Rose on rose is intrinsically close — on bare plaster it is only
     4.58 — so there is no token nudge available here, which is why this one is
     a veil where the masthead's was a veil plus a nudge.

     And the worst pixel is a DIFFERENT HUE in each house, which is the thing
     to know if this is ever retuned. SF's is a petal, rgb(217,142,162). GV's
     is a hazakura LEAF, rgb(98,147,98) — darker than anything pink, and the
     reason .55 cleared SF at 3.22 and left Guerneville at 2.83. Measuring one
     house would have shipped a wordmark that fails at the other, which is this
     file's own lesson about a value solved against one ground.

     .65 puts the wordmark at 3.48 SF / 3.17 GV and "Casa" at 4.56 / 4.16.
     Positioned absolutely on ::after rather than painted into ::before —
     that band is 190px with
     `.fd-in` pulled -86 against it, and this file already records what moving
     it costs. z-index -1 is what keeps it behind the type — .frontdoor is
     fixed with a z-index, so it is a stacking context and -1 lands above its
     own background rather than behind the page.

     It fades in and out because an edge here would read as the top of a card,
     which is the original ::before comment's reason and still true. The hold
     spans the wordmark and the date; the question below it sits in the
     fade-out and stands on the nudge alone. */
  :root[data-skin="sakura"] .frontdoor::after {
    content: "";
    position: absolute;
    z-index: -1;
    top: 76px;
    left: 0;
    right: 0;
    height: 190px;
    background: linear-gradient(180deg,
      rgba(245,243,240,0) 0,
      rgba(245,243,240,.65) 13%,
      rgba(245,243,240,.65) 65%,
      rgba(245,243,240,0) 100%);
  }

  /* MUTED TEXT CANNOT LIVE ON A PICTURE, and the proof is a ceiling rather
     than a measurement. --ink-mute is .70 and --ink-soft .72, which read 4.65
     and 4.93 on BARE plaster — a tenth of a point over AA with a flat ground
     under them. Any texture at all spends that, and no veil can give it back,
     because the best a veil can do is turn the picture back into plaster. So
     the fix is the token, not the ground: .85 wherever the ground shows.

     It is scoped to what actually sits on the plaster rather than set at the
     root, because --ink-soft has 45 consumers and all but a handful are
     inside cards, which are opaque and were measured there. `.on-ground` is
     added by groupIntoCards() off GROUND, so the list stays written once; the
     footer and the Front Door are named because they are not panel children.

     Measured against the worst pixel in each band: 4.73 over the scatter,
     5.68 over the canopy under the mist below. The masthead greeting and the
     Front Door's date each carried their own .85 before this and no longer
     need to — same number, same reason, now said once. */
  :root[data-skin="sakura"] .on-ground,
  :root[data-skin="sakura"] .footer,
  :root[data-skin="sakura"] .frontdoor {
    --ink-mute: rgba(var(--ink-rgb),.85);
    --ink-soft: rgba(var(--ink-rgb),.85);
  }

  /* THE CANOPY BAND OF THE PANEL, which is the top ~240px of it and is where
     the subnav, a scope note and a toolbar land. Even at .85 those read 3.82
     and 3.85 on the canopy's own worst pixel, so this band needs the veil as
     well as the token — the same pairing the Front Door needed, for the same
     reason, one screen over.

     .6 is Jenn's number. Her spec puts it behind the subnav alone, "because
     the labels were lost in the blossoms"; it is the whole band here, since
     the scope note and the toolbar are lost in exactly the same blossoms and
     two overlapping veils would compound into a bar brighter than either.
     It fades out rather than ending, which is this file's rule about edges
     reading as the top of a card, and it is pinned to the panel rather than
     to the page because both scroll together. */
  /* THE FRIEZE LABEL STOPS BEING THE ROOM'S COLOUR HERE, and the precedent is
     this file's own: the Shopping aisle wore --dest-text until "seven aisles
     were seven purple labels down one screen", and it became --ink-mute with
     "the room still purple in the subnav and the panel's band". Same move, one
     level up, forced by the ground rather than by repetition.

     Every room fails on the scatter — 2.93 Today, 3.14 House, 3.27 Bills,
     3.31 Calendar — and all four were solved on FLAT plaster, where they read
     5.04 to 5.69. That is the documented trap in its purest form, found in all
     five rooms at once because the costume changed what is behind them.

     Darkening five hexes was the alternative and is worse: it is five values
     to keep in step against a ground that is a picture, to colour a label that
     already has --dest tilework running off the end of it. The wayfinding is
     in the frieze, not in the word. 4.73 on the scatter's worst pixel. */
  :root[data-skin="sakura"] .section-head { color: var(--ink-mute); }

  /* A CONTROL ON A PICTURE NEEDS A SURFACE. `.btn` and `.add-open` are both
     `background: transparent` with --dest-text on top, which is right on flat
     plaster and not here: "Pull from this week's meals" measured 4.25 under
     the mist and "+ Add to the list" 3.07 further down, where only the
     scatter is behind it. Both are the room's own colour and neither can be
     darkened without doing it five times, once per room, against a ground
     that is a picture.

     Giving them the card instead fixes every room at once with no colour
     maths, and says the right thing besides — a card is what this app uses
     for "content sits on a surface", and a button on a drawing of a tree is
     the same problem one size down. 5.98 for Shopping's purple on card,
     and no room lands under 5.4.

     Scoped to .on-ground, because a button inside a card already has one.

     The house chip is the same fix for the same reason: at `--card` 72% the
     canopy came through it, which left its house dot at 1.41 against a
     blossom. Opaque, the dot is back on cream where it was designed. */
  :root[data-skin="sakura"] .on-ground .btn,
  :root[data-skin="sakura"] .on-ground .add-open {
    background: var(--card);
  }

  :root[data-skin="sakura"] .housechip { background: var(--card); }

  :root[data-skin="sakura"] .panel {
    background-image: linear-gradient(180deg,
      rgba(245,243,240,.6) 0,
      rgba(245,243,240,.6) 68%,
      rgba(245,243,240,0) 100%);
    background-repeat: no-repeat;
    background-size: 100% 250px;
  }

  /* The mist FADES IN as well as out, and the missing half of that was the
     bug Jenn found on the phone. It began at full strength on `.greet`'s
     first pixel — and `.greet`'s first pixel is exactly where the safe-area
     inset ends, so on a notched device a cream wash started on a hard line
     directly under the Dynamic Island, over blue sky, with blossoms resuming
     under it. Her words were "the pink bar at the top of the header" and
     "the blur is overlapping onto the date text", and both are that one
     edge. It is invisible in a browser and on the Mac, where the inset is 0
     and the line falls at the very top of the page with nothing above it to
     be a line against.

     26px is the ramp, which clears the date and is complete well before the
     greeting — so the greeting keeps the full .42 it was measured with, and
     reads 5.26 against the worst pixel behind it. */
  :root[data-skin="sakura"] .greet {
    background: linear-gradient(180deg,
      rgba(245,243,240,0) 0,
      rgba(245,243,240,.42) 26px,
      rgba(245,243,240,.42) 72%,
      rgba(245,243,240,0) 100%);
    border-bottom: 0;
  }

  /* The house still swaps underneath it, because "you know which house you
     are in before you have read a word" is load-bearing and a costume does
     not get to switch it off. These out-specify the plain house blocks
     above (three attributes against two) and sit after them besides. */
  :root[data-skin="acid"][data-house="sf"] {
    --house: var(--sf); --house-light: var(--sf-light); --house-text: var(--sf);
    --house-chip: rgba(61,232,240,.18); --house-edge: rgba(61,232,240,.55);
    --motif: none;
    /* Cyan house, green chrome. */
    --latao: var(--gv);
    --frieze-pattern: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='13' viewBox='0 0 9 13'%3E%3Crect x='.8' y='1.9' width='4.4' height='9.2' fill='none' stroke='%23B8F22D' stroke-opacity='.85' stroke-width='1.3'/%3E%3C/svg%3E");
  }

  :root[data-skin="acid"][data-house="gv"] {
    --ink: #E6DAFF; --ink-rgb: 230,218,255;
    --plaster: #150826; --card: #1F0F38;
    --tile: #A24BF0; --tile-rgb: 162,75,240;
    --tile-soft: #C77DFF; --tile-soft-rgb: 199,125,255;
    --glaze: #24203F; --glaze-rgb: 36,32,63;
    --tile-hover: #B869FF;
    --house: var(--gv); --house-light: var(--gv-light); --house-text: var(--gv);
    --house-chip: rgba(184,242,45,.18); --house-edge: rgba(184,242,45,.55);
    --motif: none;
    /* Green house, cyan chrome. */
    --latao: var(--sf);
    --frieze-pattern: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='13' viewBox='0 0 9 13'%3E%3Crect x='.8' y='1.9' width='4.4' height='9.2' fill='none' stroke='%233DE8F0' stroke-opacity='.85' stroke-width='1.3'/%3E%3C/svg%3E");
  }

  /* The lobby cards carry HARDCODED destination text colours, measured
     against the light theme's card ground and commented with the numbers
     ("4.88 on the card's ground"). That is the documented trap stated in the
     file itself: a token's contrast is only valid on the background it was
     measured against. On this ground the Calendar blue measured 2.09:1 and
     the label was the last thing in the app under the floor.

     They are not reachable from :root either, because a lobby card sets
     --dest on ITSELF — "a lobby card takes the colour of the destination it
     leads to" — so the cascade stops at the card. Each one has to be named. */
  /* THE MASTHEAD IS A FIELD, NOT A BAND. The checkerboard went in because
     Lisbon's masthead carries tilework, and a blocky pattern was the obvious
     translation — which made it, in Jenn's words, a picnic-table blanket. Her
     reasoning for dropping it is the better one: the masthead is already the
     only thing on screen not inside a box, so it reads as a different space
     without being told to. The pattern was saying it a second time, loudly.

     So the band goes transparent and THE DATE CARRIES THE HOUSE instead,
     which is the same substitution the rest of the costume makes — colour
     moves from a fill onto the type. Cyan in SF, acid green at Guerneville,
     and you still know which house you are in before reading a word.

     The rule under it stays --latao and stays fixed across both houses, for
     the reason the brass hairline and "Casa" already do: they are brand, not
     location. It is the one edge in the app that reads as made rather than
     drawn, and 2px of acid green is that edge speaking this dialect. */
  :root[data-skin="acid"] .masthead,
  :root[data-skin="acid"] .greet {
    background: transparent;
    background-image: none;
  }

  :root[data-skin="acid"] .today {
    color: var(--house);
    text-transform: lowercase;
    /* Exactly zero. The base tightens by .02em, which is what a serif display
       size wants; mono is already even-width and wants neither that nor the
       tracking I first gave it. The honest value, and it happens to buy the
       fit: at .02em "tuesday 15 sep" is 261px against 325 available, which
       pushed the chip onto its own line with the tack costing only 69. At 0
       it is 253 and they share a line.

       Only on the shorter weekdays — "wednesday" is two characters more than
       the budget has. That is what .greet-in's wrap is for, and it degrades
       to the chip taking its own line rather than to anything breaking. */
    letter-spacing: 0;
  }

  :root[data-skin="acid"] .hello {
    text-transform: lowercase;
  }

  /* THE DATE TAKES THE WHOLE ROW, AND THE CHIP PAIRS WITH THE GREETING.
     Jenn's layout, and it is the better one: sharing a line with the chip
     meant the date's budget depended on the day of the week, so "tuesday"
     fitted and "wednesday" — two characters more — pushed the chip onto its
     own line. A masthead that reflows on a Wednesday is a masthead you
     notice, which is the opposite of what it is for.

     Given the full width the date cannot run out: the longest it ever gets is
     "wednesday 15 sep" at 16 mono characters, 289px against 339 available.
     And the chip stops competing with the headline for a line it was always
     going to lose — it belongs with the greeting, which is the other thing up
     here that qualifies rather than announces.

     `display: contents` on the wrapper is what makes it a CSS-only change:
     .greet-text is a bare <div> with no styles and no semantics, so removing
     it from the box tree costs nothing and lets .today, .hello and the chip
     be placed as one grid. */
  /* The grid that used to live here is the base's now — the reflow it fixed
     was never the costume's, and Lisbon was doing it too. */

  /* The date-never-wraps rule moved to .greet-in and .today in the base,
     because the bug was never the costume's: Lisbon does it too, and was
     measured doing it. */

  /* THE BAR IS A FIELD WITH A RULE, LIKE THE MASTHEAD. It was the last fill
     in the costume and the loudest thing on screen — `background: var(--ink)`,
     which is the DARK ink in Lisbon and the PALE one here, so the whole bar
     inverted to near-white with dark labels and white icons on pale tiles.
     Jenn called it "a bit bright", which was generous.

     Her fix is the same shape the masthead already uses: no fill, and a rule
     to separate it. Header and footer are the two things not in a box, and
     they now bracket the app with the same 2px of --latao — one under, one
     over. The shadow goes with the fill: it was lifting the bar off a ground
     it is now part of. */
  :root[data-skin="acid"] .tabs {
    /* The GROUND's colour, not `transparent`. The bar is position:fixed, so
       transparent means the panel scrolls through it — "+ Add to the list"
       reading straight across the tab labels. It has to paint, it just has to
       paint the same colour as what it sits on. Same answer as the status
       cap, one end of the app to the other. */
    background: var(--plaster);
    background-image: none;
    border-top: 2px solid var(--latao);
    box-shadow: none;
  }

  /* The label colour derives from --glaze, which is a DARK purple here, so it
     was legible only because the bar had gone pale. Back onto ink, at the
     alpha the rest of the app's muted text uses. */
  :root[data-skin="acid"] .tab {
    color: rgba(var(--ink-rgb),.72);
  }

  /* OUTLINED IS "you could go here"; FILLED IS "you are here". The fill was
     the whole bar before and said nothing, because everything had it. Spent
     on one tab it becomes the only thing in the bar that answers "where am
     I", and it costs no new colour — it is the destination's own, which the
     outline was already wearing.

     The inset top rule came off with it. That was the selected marker while
     nothing else was one; keeping both would be two devices doing one job,
     directly above each other. */
  :root[data-skin="acid"] .tab[aria-selected="true"] {
    color: var(--ink);
    background: transparent;
    box-shadow: none;
  }

  /* --dest-ink is the text colour ON a filled --dest, which is exactly what
     this glyph is. It is the page ground here rather than the light ink — see
     the destination-axis note above, where the same inversion is spelled
     out. */
  :root[data-skin="acid"] .tab[aria-selected="true"] .tab-tile {
    background: var(--dest);
    border-color: var(--dest);
    color: var(--dest-ink);
  }

  /* OUTLINED, NOT FILLED — the same substitution as everywhere else, and the
     last place it had not reached. Each tab sets its own --dest, so the
     outline and the glyph both take the destination's colour and the
     wayfinding survives losing the fill: tapping a terracotta icon still
     lands you somewhere terracotta. White-on-tile is gone with it, which was
     a pale glyph on a pale tile. */
  :root[data-skin="acid"] .tab-tile {
    background: transparent;
    border: 1px solid var(--dest);
    color: var(--dest);
    border-radius: 0;
  }

  /* iOS draws the clock and battery in WHITE over this strip, so it has to
     stay dark. It takes --tile in Lisbon, which is violet here and would put
     white on a mid-tone. The page ground is the right answer and disappears
     into the field, which is what a transparent masthead wants anyway. */
  :root[data-skin="acid"] .status-cap {
    background: var(--plaster);
  }

  /* Mono is wider than the sans at the same rung, so the door's question
     broke mid-phrase — "Como vai hoje? \u00b7 How's / today?". This file already
     ruled on that shape once, for the short list's head: a title that breaks
     mid-phrase "reads as broken rather than tight". One rung down on the
     ladder fits it on one line, and it stays ON the ladder rather than
     declaring a size, which is the rule that keeps the scale at eleven.

     The brand drops a rung for the same reason and to keep its proportion to
     the question. Both are scoped to the costume; the Lisbon sizes are
     untouched. */
  :root[data-skin="acid"] .fd-q { font-size: var(--fs-lead-name); }
  :root[data-skin="acid"] .fd-q b { font-size: var(--fs-large); }
  :root[data-skin="acid"] .fd-brand { font-size: var(--fs-display); }

  :root[data-skin="acid"] .tonight-label { color: var(--t-doc); }
  :root[data-skin="acid"] .tonight .btn { --dest-text: var(--t-doc); }
  :root[data-skin="acid"] .callout-k,
  :root[data-skin="acid"] .callout-go { color: var(--t-upkeep); }

  /* NOTHING IS ROUNDED. There is no radius token — 38 literal declarations —
     and adding one to the base design for a costume is the tail wagging the
     dog, so the skin names the boxes instead. The check rings are
     deliberately absent from this list: they are circles in every world, and
     so is the day-marker dot. */
  :root[data-skin="acid"] .card,
  :root[data-skin="acid"] .shortlist,
  :root[data-skin="acid"] .sl-card,
  :root[data-skin="acid"] .rec,
  :root[data-skin="acid"] .pick,
  :root[data-skin="acid"] .restore,
  :root[data-skin="acid"] .data-block,
  :root[data-skin="acid"] .btn,
  :root[data-skin="acid"] .chip,
  :root[data-skin="acid"] .fd-level,
  :root[data-skin="acid"] .wk-cell,
  :root[data-skin="acid"] .mo-cell,
  :root[data-skin="acid"] .tonight,
  :root[data-skin="acid"] .callout,
  :root[data-skin="acid"] .picker-list,
  :root[data-skin="acid"] input,
  :root[data-skin="acid"] select,
  :root[data-skin="acid"] textarea {
    border-radius: 0;
  }

  /* A BOX IS AN OUTLINE, NEVER A FILL. Warm shadows read as dirt on plaster;
     here they read as nothing at all, and a glow would just be a soft edge on
     something that should be a hard one. */
  :root[data-skin="acid"] .card,
  :root[data-skin="acid"] .shortlist,
  :root[data-skin="acid"] .sl-card,
  :root[data-skin="acid"] .restore,
  :root[data-skin="acid"] .picker-list {
    background: transparent;
    border: 1px solid var(--wire);
    box-shadow: none;
  }

  /* Rows inside a box get no box of their own — that would be a table, and
     the separator is already doing the work. */
  :root[data-skin="acid"] .rec,
  :root[data-skin="acid"] .fd-level,
  :root[data-skin="acid"] .pick {
    background: transparent;
  }

  :root[data-skin="acid"] .fd-level,
  :root[data-skin="acid"] .pick {
    border: 1px solid var(--wire);
  }

  /* The lobby cards carried their destination as an 18% TINT. That is the
     clearest case of the thing being removed: the colour moves to the rule
     and the label, which were already carrying it. */
  :root[data-skin="acid"] .tonight {
    background: transparent;
    /* 68 rather than 55: at 55 the edge measured 2.98:1 against the
       ground, which is the 3:1 control-boundary floor missed by two
       hundredths. It is the only thing saying where this card is. */
    border: 1px solid color-mix(in srgb, var(--t-doc) 92%, transparent);
  }

  :root[data-skin="acid"] .callout-chores {
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--t-upkeep) 92%, transparent);
  }

  /* Calendar cells are a grid of outlines, which is what a week strip wants
     to be anyway. */
  :root[data-skin="acid"] .wk-cell,
  :root[data-skin="acid"] .mo-cell {
    background: transparent;
    border: 1px solid var(--rule);
  }

  /* EXCEPT the house tint, which the rule above had been eating. The base
     sets it as `.wk-cell.wk-house-gv` — (0,2,0), deliberately carrying the
     cell class so it "outranks the plain background whatever order the rules
     end up in" — and a skin selector is (0,2,1), which outranks THAT. So the
     costume silently removed the one thing on the calendar that says a day
     belongs to the other house.

     Worth noting what the base comment already warns about: these tints are
     emitted only for days at the house you are NOT at, so at most one is on
     screen and it always reads against the plain ground. That is what lets
     them be this light. */
  :root[data-skin="acid"] .wk-cell.wk-house-sf,
  :root[data-skin="acid"] .mo-cell.mo-house-sf { background: var(--cell-sf); }
  :root[data-skin="acid"] .wk-cell.wk-house-gv,
  :root[data-skin="acid"] .mo-cell.mo-house-gv { background: var(--cell-gv); }

  /* Chips stop being tinted lozenges and become bracketed text in the type's
     own colour — the type pill was a 16% wash of --edge under a mixed-down
     version of the same hue, which is two ways of saying it where a terminal
     uses one. */
  :root[data-skin="acid"] .chip {
    background: transparent;
    border: 1px solid currentColor;
  }

  :root[data-skin="acid"] .chip-type {
    color: var(--edge, var(--tile-soft));
    background: transparent;
  }

  /* The effort scale is three HARDCODED values solved for cream — #1F5F55 is
     a dark teal, and on this ground "EASY" measured 1.6:1. The same family as
     the lobby cards' hexes and the destination text: a token's contrast is
     only valid on the background it was measured against, and a costume that
     inverts the ground invalidates every one of them at once.

     It stays a SCALE, which is the thing about it worth preserving — three
     steps that read as steps. Mint, violet, amber: cool to warm as the work
     gets bigger, which is the same direction the light theme runs. */
  /* The record's own house, and the SEVENTH pair of values solved against
     cream: #1B4570 and #256349 are a dark blue and a dark green, which on
     this ground are all but invisible. They take the house colours
     themselves, which are already bright here and already mean this.

     The washes go with every other fill — the .chip rule above has taken
     those — so what is left is the letters and a hairline, which is what a
     chip is in this costume. */
  :root[data-skin="acid"] .chip-sf { color: var(--sf); }
  :root[data-skin="acid"] .chip-gv { color: var(--gv); }

  :root[data-skin="acid"] .chip-easy {
    color: #5BE8A8;
    border-color: rgba(91,232,168,.55);
  }

  :root[data-skin="acid"] .chip-project {
    border-color: rgba(255,182,39,.55);
  }

  /* Still filled, and deliberately: "on a bad day this is the one meal fact
     worth finding at a glance". The one fill the costume keeps, for the same
     reason the base keeps it. */
  :root[data-skin="acid"] .chip-nocook {
    color: #5BE8A8;
    border-color: rgba(91,232,168,.55);
    background: rgba(91,232,168,.16);
  }

  /* The form's own wash goes with the rest of the fills; the field borders
     are what say where a field is, and they are already measured for it. */
  :root[data-skin="acid"] .form {
    background: transparent;
  }

  :root[data-skin="acid"] input,
  :root[data-skin="acid"] select,
  :root[data-skin="acid"] textarea {
    background: transparent;
  }

  /* The Facts house filter fills with the house it selects, so the control
     says which house it means twice over — by word and by colour. */
  .facts-toggle .btn-fill[data-house="sf"] { background: var(--sf); border-color: var(--sf); }
  .facts-toggle .btn-fill[data-house="gv"] { background: var(--gv); border-color: var(--gv); }

  /* "All" has no house colour, so it had no rule — and therefore never
     filled at all. `.facts-toggle .btn` sets the quiet background at (0,2,0),
     which beats `.btn-fill` at (0,1,0); the two above win it back at (0,3,0)
     and this one was simply missing. Selected, it was white type on a 4% ink
     wash in Lisbon and dark type on the same in the costume, which is where
     Jenn spotted it: "it actually almost disappears when you click on it".
     1.07:1 there.

     It takes the ROOM's colour, which is the honest answer for a control that
     means "both houses": there is no third house colour to reach for, and the
     room is the one thing on screen that is already about where you are
     rather than which house a record belongs to. */
  .facts-toggle .btn-fill[data-house="all"] {
    background: var(--dest, var(--tile));
    border-color: var(--dest, var(--tile));
  }

  /* ---------- buttons ---------- */

  button {
    font-family: var(--ui);
    cursor: pointer;
  }

  .btn {
    appearance: none;
    border: 1px solid var(--dest, var(--tile));
    background: transparent;
    color: var(--dest-text, var(--dest, var(--tile)));
    font-size: var(--fs-body);
    font-weight: 500;
    padding: 8px 12px;
    border-radius: 3px;
    min-height: 40px;
    white-space: nowrap;
  }

  .btn:hover { background: color-mix(in srgb, var(--dest, var(--tile)) 10%, transparent); }

  /* The primary button belongs to the room, like everything else the
     destination colours. --dest-ink exists because Today's gold cannot carry
     white text — it measures about 2:1, well under the floor. */
  .btn-fill {
    background: var(--dest, var(--tile));
    color: var(--dest-ink, #fff);
    border-color: var(--dest, var(--tile));
  }

  .btn-fill:hover { background: color-mix(in srgb, var(--dest, var(--tile)) 86%, #000); }

  .btn-quiet {
    border-color: transparent;
    color: var(--ink-soft);
    font-weight: 400;
    padding: 8px 8px;
  }

  .btn-quiet:hover { background: rgba(var(--ink-rgb),.05); color: var(--ink); }

  .ico { display: block; }

  .btn-ico { padding: 8px; min-width: 0; }

  /* The row's tick is a touch smaller than the lobby's — a list you scan is
     denser than three cards you're being handed. */
  /* --edge has to be defined here, not patched on the tick: .sl-check sets
     `border: 2.5px solid var(--edge)`, and an undefined custom property
     invalidates the entire shorthand — taking border-style with it, which is
     why the ring vanished rather than merely losing its colour. */
  .rec-check-row { align-items: flex-start; --edge: var(--t-todo); }

  /* A scheduled row carries no check and is NOT indented to line up with the
     checked ones. The row it should match is Dinner, which has no ring
     either — reserving the space made appointments look like something was
     missing rather than like something that needs nothing from you. */
  .rec-bill   { --edge: var(--t-bill); }
  .rec-upkeep { --edge: var(--t-upkeep); }
  .rec-doc    { --edge: var(--t-doc); }
  .rec-appt   { --edge: var(--t-appt); }
  .rec-check-row .rec-tick:hover { background: color-mix(in srgb, var(--edge) 18%, transparent); }
  /* The ring is neutral at rest and takes the record's own colour on the way
     out — the app's one authored motion moment, unchanged. Type on a ring
     was never wrong as a signal, only as a permanent one. */
  .sl-check.is-filling, .rec-tick.is-filling { border-color: var(--edge); }

  /* A finished row keeps its ring, filled — the left column stays aligned
     whether or not the thing is done. */
  .rec-tick-done { background: var(--edge); opacity: .5; }
  .rec-tick { width: 23px; height: 23px; border-width: 2.2px; margin-top: 1px; }


  .btn-sm { font-size: var(--fs-body); min-height: 36px; padding: 6px 10px; }

  :focus-visible {
    outline: 2px solid var(--dest, var(--tile));
    outline-offset: 2px;
  }

  /* ---------- add row ---------- */

  .addbar { padding: 13px 16px 16px; }

  .add-open {
    width: 100%;
    text-align: left;
    border: 1px dashed rgba(var(--ink-rgb),.3);
    background: transparent;
    color: var(--dest-text, var(--dest, var(--tile)));
    font-size: var(--fs-large);
    padding: 13px 16px;
    border-radius: 13px;
    min-height: 46px;
  }

  .add-open:hover { background: color-mix(in srgb, var(--dest, var(--tile)) 7%, transparent); border-color: var(--dest, var(--tile)); }

  /* The form is a distinct surface rather than fields floating on the panel:
     tinted with the room, ruled, and inset. It's the difference between "this
     list has a form under it" and "you are filling something in". */
  .form {
    display: grid;
    gap: 11px;
    background: color-mix(in srgb, var(--dest, var(--tile)) 7%, var(--card));
    border: 1px solid color-mix(in srgb, var(--dest, var(--tile)) 22%, transparent);
    border-radius: 7px;
    padding: 14px;
  }

  /* Paired fields sit side by side only where that leaves them readable. The
     basis was 120px, which two fields could satisfy inside a phone-width
     panel — so a recipe's "Ahead of time" or a bill's "What" ended up about
     half an inch wide, too narrow to read what you'd typed. At 200px two
     fields no longer fit on a phone and the row wraps to one each, while a
     tablet or desktop panel still pairs them. Both selectors carry the basis
     because `label.field` outranks `.form-row > *`; changing only one is a
     silent no-op. */
  .form-row { display: flex; gap: 10px; flex-wrap: wrap; }
  .form-row > * { flex: 1 1 200px; min-width: 0; }

  /* div.field too: a field that carries a Clear control cannot be a <label>,
     because a button inside one activates the labelled input — which for a
     date input is the picker this control exists to get out of. */
  label.field,
  div.field {
    display: block;
    flex: 1 1 200px;
  }

  /* The label row of a clearable field: its own label on the left, the way
     out on the right. Only this variant becomes a row, so every other field
     label keeps the plain block it has always been. */
  .field-clearable .field-label {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
  }

  /* A .linkish, which is the app's existing quiet text action — and the
     underline rather than a colour is what makes it read as a control.

     It went in wearing --dest-text, the room's own colour, and that was a
     straight repeat of the trap this file documents: a token's contrast is
     only valid on the ground it was measured against. Gold measured 5.20 on
     the form's wash in Today and the identical rule measured 3.49 in House,
     where --dest-text is terracotta — under AA, on the one room where
     "Deadline" actually lives. Spending a wayfinding colour on a small piece
     of form chrome bought nothing and had to be right in five rooms.
     --ink-soft is what the label beside it already wears.

     Only the size and the hit area are this rule's own business now — and
     the selector carries .field-clearable so it outranks .linkish's own
     padding: 0 whatever order the two rules end up in. Matching weight and
     trusting source order is how the clear control came out 32x15 with no
     hit area at all on the first attempt. */
  .field-clearable .field-clear {
    font-size: var(--fs-label);
    /* The hit area grows UP and sideways and stops at the label's own 5px
       bottom margin, which is deliberate rather than tidy. 24px was the
       height this went in at, and this file already calls 24 "roughly half
       the 44px minimum, on the app built for days when hands are unsteady".
       Taking the rest of it downward was the obvious move and is the wrong
       one: it would put Clear over the top edge of the date input, so a
       thumb reaching for the picker would sometimes empty the field instead.
       A slightly small target beats one that destroys what you were aiming
       at. The negative margins hold the label on the line every other field
       label sits on. */
    padding: 14px 8px 5px;
    margin: -14px -8px -5px;
    cursor: pointer;
  }

  /* Mono uppercase, matching the section heads, group labels and tags. It reads as
     finished because it's the voice every other small label in the app already
     speaks — consistency beat the readability argument for switching it. */
  .field-label {
    display: block;
    font-family: var(--mono);
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--ink-soft);
    margin-bottom: 5px;
  }

  /* A checkbox row reads as a statement, not a labelled field. */
  .field-check {
    flex: none;
    display: flex;
    align-items: center;
    /* 24px was the whole row, which is a small target for a thumb on a bad
       day — and this is the app for bad days. The label is the target, so it
       was 340 wide and 24 tall; only the height needed solving. 40 rather
       than 44: the box is 22 and the rest is air, so the last four pixels
       bought nothing you could feel and spread the run out. */
    min-height: 40px;
    padding: 0;
  }

  /* A RUN of them is one block rather than three unrelated fields. The form is
     a grid with one gap, so a title, a pair of selects and three flags all sat
     exactly 11px apart and nothing said which belonged together — the same
     shape as the list-rhythm problem, where uniform spacing meant no grouping.

     Cancelling the gap is the whole of it: touching rows are one group of
     three and the untouched 11px either side is the boundary. A hairline
     between them was tried and taken out — it is this app's own section-head
     lesson, that the space IS the pause and a rule saying it again is the
     thing that makes a group read as a fence. It also could not sit anywhere
     good: the box is 22px in a 40px row, so the rule lands right against the
     checkbox with nowhere to go.

     Done here rather than by wrapping each run in a container, because runs
     appear in four forms with different memberships — to-dos, upkeep, chores
     and bills — and that is four places to get it wrong and four to forget
     when a fifth form grows a checkbox. Same reasoning groupIntoCards() uses.

     Scoped to .form so the data screen keeps its own spacing: there a
     checkbox is a setting under the paragraph explaining it, not a flag in a
     run. */
  .form .field-check + .field-check { margin-top: -11px; }

  /* Inside a data block it is a setting rather than a form row, and it needs
     separating from the paragraph that explains the setting above it. */
  .data-block .field-check { margin-top: 16px; }

  .field-check .field-label {
    display: flex;
    align-items: center;
    gap: 9px;
    margin: 0;
    font-family: var(--ui);
    font-weight: 500;
    font-size: var(--fs-body);
    letter-spacing: normal;
    text-transform: none;
    color: var(--ink);
    cursor: pointer;
  }

  .field-check input[type="checkbox"] {
    width: 20px;
    height: 20px;
    min-height: 0;
    flex: none;
    margin: 0;
    accent-color: var(--dest, var(--tile));
  }

  /* Four fixed options, so four thumb-sized targets beat a multi-select the
     way the fact picker uses one — that list is unbounded, this one never
     will be. Real checkboxes underneath the labels, so it needs no JS, stays
     keyboard-reachable, and the whole chip is the hit area. */
  .demands { display: flex; flex-wrap: wrap; gap: 7px; }
  .demand { position: relative; display: inline-flex; }

  .demand input[type="checkbox"] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    min-height: 0;
    margin: 0;
    opacity: 0;
    cursor: pointer;
  }

  .demand span {
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: .07em;
    text-transform: uppercase;
    border: 1px solid rgba(var(--ink-rgb),.56);
    border-radius: 99px;
    padding: 9px 13px;
    color: var(--ink-soft);
    cursor: pointer;
    transition: background .13s ease-out, color .13s ease-out, border-color .13s ease-out;
  }

  /* --dest-ink is the text colour ON a filled --dest, which is what this is.
     Bare --dest as type would be 2.24:1 in Today, where this form lives. */
  .demand input:checked + span {
    color: var(--dest-ink, #fff);
    background: var(--dest, var(--tile));
    border-color: var(--dest, var(--tile));
  }

  .demand input:focus-visible + span {
    outline: 2px solid var(--dest, var(--tile));
    outline-offset: 2px;
  }

  /* Control boundaries are .50 and that number is measured, not chosen.
     WCAG 1.4.11 wants 3:1 for the edge that tells you a control is there, and
     ink crosses 3:1 at .56 over the tint these controls actually sit on — .22, where
     this sat, measured 1.53. The label above a field is not a substitute:
     the border is the only thing marking where the field actually is.

     It reads heavier than the hairline it replaced, and better — the fields
     had been vague shapes rather than fields. Do not soften it back without
     re-measuring. */
  input, select, textarea {
    width: 100%;
    font-family: var(--ui);
    font-size: var(--fs-input);
    color: var(--ink);
    background: var(--card);
    border: 1px solid rgba(var(--ink-rgb),.56);
    border-radius: 5px;
    padding: 11px 12px;
    min-height: 46px;
    transition: border-color .12s ease-out, box-shadow .12s ease-out;
  }

  input::placeholder, textarea::placeholder { color: var(--ink-mute); }

  /* Figures are typed as well as read: a date, an amount or a filter size gets
     the mono face in the field too, not only in the record. */
  input[type="date"], input[type="time"], #f-amount { font-family: var(--mono); }

  textarea { min-height: 76px; line-height: 1.45; padding-top: 10px; }

  input:focus, select:focus, textarea:focus {
    border-color: var(--dest, var(--tile));
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--dest, var(--tile)) 22%, transparent);
  }

  .form-actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    align-items: center;
    margin-top: 3px;
    padding-top: 12px;
    border-top: 1px solid color-mix(in srgb, var(--dest, var(--tile)) 18%, transparent);
  }

  .form-actions .btn { min-height: 44px; padding: 10px 18px; font-size: var(--fs-large); }

  /* A row swapped out for its edit form — tinted so it's obvious which record
     you're changing when the list is long. */
  .rec-editing {
    display: block;
    background: rgba(var(--glaze-rgb),.32);
    padding: 12px 16px 14px;
  }

  /* A note about the thing above it, so it needs air. The -3px it used to
     carry was earned in one place — directly under a form field, where it
     reads as part of the field — and wrong everywhere else. On the data
     screen it sat under button rows and checkboxes, and a hint touching the
     control it explains is most of why that screen read as a wall. */
  .form-hint {
    font-size: var(--fs-body);
    line-height: 1.45;
    color: var(--ink-soft);
    margin-top: 10px;
  }

  .field + .form-hint { margin-top: -3px; }
  .form-hint + .field,
  .form-hint + .field-check { margin-top: 14px; }
  .field-check + .form-hint { margin-top: 7px; }

  /* On the plaster, like the subnav above it. The tint and the hairline were
     what made it a band inside a box; there is no box now, and a tinted strip
     under the subnav's own former tint was two chrome bands stacked. */
  .facts-bar {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
    padding: 10px 3px 4px;
    background: transparent;
    border-bottom: 0;
  }

  /* Softer and rounder than a form button, because this is a filter and not
     an action — and it is the one control in the app that keeps the pill
     shape, now that navigation is underlined everywhere. The resting state is
     a tint rather than an outline so the selected house is the only filled
     thing in the row. */
  .facts-toggle { display: flex; gap: 5px; }

  .facts-toggle .btn {
    font-size: var(--fs-body);
    font-weight: 500;
    min-height: 36px;
    padding: 6px 12px;
    border-radius: 9px;
    border-color: rgba(var(--ink-rgb),.14);
    background: rgba(var(--ink-rgb),.04);
    color: var(--ink-soft);
  }

  .facts-toggle .btn-fill { color: var(--house-ink); }

  .facts-bar input {
    flex: 1;
    min-width: 130px;
    width: auto;
    font-size: var(--fs-body);
    min-height: 36px;
    padding: 7px 11px;
    border-radius: 9px;
  }

  /* Figures get the mono face, per the typography rule. */
  .fact-value { font-family: var(--mono); }

  /* A fact row's value, note and path are three different kinds of thing, and
     middot-joining them made a fact read as a paragraph you had to parse. A
     line each, with a hanging indent so a wrapped path stays visibly attached
     to the line it belongs to. Taller, and worth it: you can find the value
     without reading the rest. */
  .fact-line { display: block; padding-left: 12px; text-indent: -12px; }
  .fact-line + .fact-line { margin-top: 4px; }
  .fact-line::before { content: "\00b7\00a0"; color: var(--ink-soft); }

  /* Each linked fact is its own line with a hanging indent, so a value that
     wraps is visibly a continuation rather than the next fact. */
  .fact-inline {
    display: block;
    font-family: var(--mono);
    padding-left: 13px;
    text-indent: -13px;
  }

  .fact-inline + .fact-inline { margin-top: 5px; }

  .fact-inline-label { color: var(--ink-soft); }
  .fact-inline-label::after { content: ":\00a0"; }
  .fact-inline::before { content: "\00b7\00a0"; color: var(--ink-soft); }
  .fact-file { color: var(--ink-soft); }

  /* ---------- the steps on a to-do that has them ----------
     Only ever on a detail card, which is a reading view you chose to open —
     the same consent the three-item cap and the day view already turn on.
     The ring is smaller than the card's own, because the card's ring
     completes the RECORD and these complete one sitting of it; the size is
     the whole of what says which is subordinate.

     No count anywhere, and no bar. The list is the list. */
  .step {
    display: flex;
    align-items: flex-start;
    gap: 9px;
  }

  .step + .step { margin-top: 7px; }

  /* --edge is NOT defined on a to-do detail card (only .rec-check-row and the
     four .rec-* types set one), so the fallback goes INSIDE the reference.
     Declaring --edge on .step-tick instead would shadow any ancestor that
     does define one — the documented opposite mistake. */
  .step-tick {
    appearance: none;
    position: relative;
    flex: none;
    width: 18px;
    height: 18px;
    margin-top: 4px;
    border: 2px solid rgba(var(--ink-rgb),.56);
    border-radius: 50%;
    background: transparent;
    cursor: pointer;
    padding: 0;
    min-height: 0;
  }

  /* The ring stays the size it looks; the target grows to 44px around it.
     Same bargain .sl-check makes, and it matters more here — these sit in a
     run, so a miss lands on the neighbouring step rather than on nothing. */
  .step-tick::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
  }

  .step-tick:hover {
    background: color-mix(in srgb, var(--edge, var(--t-todo)) 18%, transparent);
  }

  .step-done .step-tick {
    background: var(--edge, var(--t-todo));
    border-color: var(--edge, var(--t-todo));
  }

  .step-done .step-text {
    color: var(--ink-soft);
    text-decoration: line-through;
    text-decoration-thickness: 1px;
  }

  .step-text { flex: 1; min-width: 0; }

  /* Sits under the footer, hidden until asked for. Deliberately plain: this
     is the one screen you reach for when something has already gone wrong,
     so it should look like a form and not like an alarm. */
  .restore {
    padding: 12px 16px 14px;
    border-top: 1px solid var(--rule);
    background: var(--card);
  }

  .restore textarea {
    width: 100%;
    font-family: var(--mono);
    font-size: var(--fs-body);
  }

  .restore-note {
    font-family: var(--ui);
    font-size: var(--fs-body);
    line-height: 1.45;
    color: var(--ink-soft);
    margin: 7px 0 0;
    min-height: 1.45em;
  }

  .restore-acts { display: flex; gap: 8px; margin-top: 10px; }

  .discards { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--rule); }

  .discard-row {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 10px;
    padding: 8px 0;
    border-bottom: 1px solid var(--rule);
  }

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

  .discard-when { font-family: var(--mono); font-size: var(--fs-body); color: var(--ink); }

  .discard-what {
    flex: 1;
    min-width: 0;
    font-family: var(--ui);
    font-size: var(--fs-body);
    color: var(--ink-soft);
  }

  .discard-acts { display: flex; gap: 6px; }

  /* Why this version exists, in the meta voice — a rescued conflict and a
     daily rollback point are answers to the same question, but you want to
     know which you're looking at before you replace everything with it. */
  .discard-why {
    display: block;
    font-family: var(--mono);
    font-size: var(--fs-label);
    color: var(--ink-soft);
    margin-top: 2px;
  }

  /* The reading view. Deliberately not a form: no boxes, no focus rings,
     nothing that looks like it will accept a keystroke. Each value gets its
     own labelled row so a record reads as fields rather than as a paragraph,
     which is what four stacked lines of prose had turned it into. */
  /* An opened record lifts out of the list rather than growing a bar down
     its side. Two reasons, and the second is the real one: opening is a
     change of elevation, not a change of category — the ring and the wash
     already say which type this is. And the app had two different left-rule
     meanings, "this can't be put off" and "this is open", which left neither
     of them meaning anything. The oxblood rule is now the only one. */
  .rec-detail {
    display: block;
    position: relative;
    z-index: 1;
    margin: 10px 6px;
    border-radius: 6px;
    padding: 20px 18px 18px;
    background: color-mix(in srgb, var(--edge, var(--tile)) 6%, var(--card));
    box-shadow:
      0 0 0 1px color-mix(in srgb, var(--edge, var(--tile)) 22%, transparent),
      0 1px 2px rgba(120,86,40,.10),
      0 8px 18px -10px rgba(120,86,40,.34);
  }

  /* The name and its ring are what the card IS; everything under the rule is
     what's known about it. A hairline plus real space does more for that
     separation than any amount of type weight. */
  .detail-head {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    margin-bottom: 16px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--rule);
  }

  .detail-head .rec-name { flex: 1; min-width: 0; }

  .detail-list {
    margin: 0;
    display: grid;
    gap: 15px;
  }

  /* Label above value, not beside it: at phone width a side-by-side pair
     leaves the value about twelve characters wide, which is how a document
     path ends up seven lines tall. */
  .detail-row { display: block; }

  .detail-row dt { margin-bottom: 4px; }

  .detail-value {
    margin: 0;
    font-family: var(--ui);
    font-size: var(--fs-large);
    line-height: 1.45;
    color: var(--ink);
    overflow-wrap: anywhere;
  }

  .detail-none {
    font-family: var(--ui);
    font-size: var(--fs-body);
    color: var(--ink-soft);
  }

  .detail-acts { display: flex; align-items: center; gap: 8px; margin-top: 14px; }

  /* Pushed to the far end: destructive, and it should never be the button
     you hit reaching for Close. */
  .detail-del { margin-left: auto; color: var(--oxblood); }

  /* A text link, not a button: this is a way out of the app's normal
     surfaces rather than an action, and it should carry no weight in a
     footer whose whole job is being ignorable. */
  .linkish {
    appearance: none;
    border: 0;
    background: transparent;
    padding: 0;
    font-family: var(--ui);
    font-size: var(--fs-body);
    color: var(--ink-soft);
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
    min-height: 0;
  }

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

  /* The About line at the foot of the data screen. Mono because it is a
     figure, which is the rule, and --ink-mute because it is the quietest
     thing on the screen: it is read once when something is wrong and ignored
     every other time. Centred and last, the same shape the footer's own link
     takes, because it belongs to no section above it. */
  .data-version {
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--ink-mute);
    text-align: center;
    padding: 26px 3px 4px;
  }

  /* The screen's title, on the plaster rather than in a card of its own. It
     is chrome — the same job the masthead date does on every other screen —
     and a title bar wrapped as a card read as an empty first record. */
  .data-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 4px 3px 2px;
    background: transparent;
  }

  .data-title {
    font-family: var(--serif);
    font-size: var(--fs-lead-name);
    font-weight: 600;
  }

  .data-block { padding: 13px 16px 15px; }

  /* Pairing is two steps with a trip to another browser in between, and the
     second step has to read as a second step — the code field sat directly
     under the Connect button and looked like part of it. Space rather than a
     rule, for the reason the checkbox runs learned: the pause is the space. */
  .cal-step2 { margin-top: 22px; }

  .data-block textarea,
  .data-block input[type="url"] {
    width: 100%;
    font-family: var(--mono);
    font-size: var(--fs-body);
  }

  /* ---------- footer / undo ---------- */

  /* `margin-top: auto` rather than a fixed gap, so the footer takes the
     slack in the stacked column and sits on the bottom of a short page
     instead of floating halfway up it. The gap moves to padding, which the
     auto margin cannot swallow. Declared here rather than beside .wrap
     because this rule is later in the file and would win anyway. */
  /* A centred stack at the very bottom, not a row. Data & sync is the app's
     escape hatch and belongs to no room — it is not the "next page" from
     anywhere, so borrowing the right-aligned forward-link convention said
     something untrue about it. Centred and last is what a footer is.

     `space-between` was also why it wandered: the save and sync status shared
     a line with it, so the link moved sideways whenever the app had something
     to report. Stacked, status pushes it DOWN by a predictable line instead,
     and the link keeps one position.

     The padding is what separates it from the panel — it is a different kind
     of thing from the content above, and there is no rule to say so. */
  .footer {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 4px;
    margin-top: auto;
    padding: 44px 16px 4px;
    font-family: var(--mono);
    font-size: var(--fs-lead);
    color: var(--ink-mute);
  }

  /* Truly empty rather than &nbsp;, so they take no line when there is
     nothing to say. In the old row layout the space was reserved to stop the
     link jumping sideways; stacked, reserving it is two blank lines. */
  #saveState:empty, #syncState:empty, #shellState:empty { display: none; }

  /* The status lines are one kind of thing and the link is another, so the
     link gets more air than they give each other. Collapses to nothing when
     there is no status, since the gap only applies between siblings. */
  .footer #dataOpen { margin-top: 6px; }

  .undo {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    bottom: calc(env(safe-area-inset-bottom) + 16px);
    background: var(--ink);
    color: var(--glaze);
    border-radius: 4px;
    padding: 10px 12px 10px 16px;
    display: flex;
    align-items: center;
    gap: 14px;
    font-size: var(--fs-body);
    box-shadow: 0 10px 26px -10px rgba(var(--ink-rgb),.6);
    z-index: 40;
    max-width: calc(100% - 32px);
  }

  .undo button {
    appearance: none;
    background: transparent;
    border: 1px solid var(--tile-soft);
    color: var(--glaze);
    font-size: var(--fs-body);
    padding: 6px 12px;
    border-radius: 3px;
    min-height: 36px;
  }

  /* ---------- tonight strip ---------- */

  .tonight {
    position: relative;
    display: flex;
    align-items: center;
    gap: 13px;
    background: color-mix(in srgb, var(--t-doc) 18%, var(--card));
    border: 0;
    border-radius: 17px;
    box-shadow:
      0 1px 2px rgba(120,86,40,.10),
      0 10px 24px -14px rgba(120,86,40,.30);
    padding: 13px 15px 13px 26px;
    margin: 0 0 22px;
    overflow: hidden;
  }

  /* A stack of glaze stripes, the way tiles run down a door jamb. */
  .tonight::before {
    content: "";
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 13px;
    background: repeating-linear-gradient(
      to bottom,
      var(--t-bill) 0 11px,
      var(--t-todo) 11px 22px,
      var(--t-upkeep) 22px 33px,
      var(--t-meal) 33px 44px);
  }

  /* The meal is a name like any other name, so it carries the same weight the
     short-list items do rather than sitting a size below them. */
  .tonight-meal {
    font-family: var(--serif);
    font-size: var(--fs-name);
    font-weight: 600;
    line-height: 1.25;
    color: var(--ink);
    flex: 1;
    min-width: 0;
  }

  /* DINNER TONIGHT takes its own line when the CARD is narrow, not when the
     screen is. This was `@media (max-width: 560px)`, and the viewport was a
     fair proxy for the card's width while the lobby was always the full width
     of whatever it sat in. It stopped being one the moment the lobby became a
     rail: at 1440 the viewport says "roomy" and the card is 356, so all three
     items stayed on one line and the meal name was crushed into 110px — four
     lines of "Chicken thighs with rice" beside a Change button, on the widest
     screen the app runs on and never on the phone.

     The alternative was to restate the stacked rule inside the rail block and
     the folded-lobby block, which is two more writers of one rule and a third
     the next time the lobby is arranged differently. A container query is one
     writer that is true at every width in every shell, which is the same
     argument :has() and the derived house already win here. */
  #tonight { container-type: inline-size; container-name: tonight; }

  @container tonight (max-width: 560px) {
    .tonight { flex-wrap: wrap; row-gap: 7px; }
    .tonight-label { flex: 0 0 100%; }
  }

  .tonight-label {
    font-family: var(--mono);
    font-size: var(--fs-label);
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: #42618E;   /* Calendar's --dest-text: 4.88 on the card's ground */
    flex-shrink: 0;
  }

  .tonight-meal .none { color: var(--ink-soft); font-style: italic; }

  /* The button belongs to the card, and the card is Calendar's. Left on the
     room's own --dest it came out gold on blue, which is Today's colour
     appearing on the one card in the lobby that isn't about today. */
  .tonight .btn {
    --dest: var(--t-doc);
    --dest-text: #42618E;
  }

  /* The prep line sits inside .tonight-meal, which is 600 so the meal name
     carries the weight the short list's names do. The note underneath is not
     a name and was inheriting it, which put two bold things on one card. */
  .tonight .rec-meta { font-weight: 400; }

  /* ---------- lobby callouts ----------
     A card in the lobby takes the colour of the destination it leads to:
     Tonight is Calendar's indigo, cleaning is House's terracotta. That is the
     app's own wayfinding rule — "tapping a terracotta icon lands you somewhere
     terracotta" — applied one level out, so the ground answers "where does
     this go?" before any of the words do.

     Both are their destination at 18% over card, which lands them at the same
     lightness (0.76) as the salmon Tonight used to wear. The pair keeps the
     weight of the card that was already right; only the hue changes.

     No striped jamb here. That stays Tonight's, as the one ratified exception
     to no-spines — a second one makes both meaningless. */
  .callout {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    row-gap: 3px;
    width: 100%;
    text-align: left;
    border: 0;
    border-radius: 17px;
    padding: 13px 15px 14px;
    margin: 0 0 22px;
    cursor: pointer;
    box-shadow:
      0 1px 2px rgba(120,86,40,.10),
      0 10px 24px -14px rgba(120,86,40,.30);
  }

  .callout-chores { background: color-mix(in srgb, var(--t-upkeep) 18%, var(--card)); }

  .callout-k {
    grid-column: 1;
    font-family: var(--mono);
    font-size: var(--fs-label);
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: #A8441F;   /* House's --dest-text: 4.61 on the card's ground */
  }

  .callout-line {
    grid-column: 1;
    font-family: var(--serif);
    font-size: var(--fs-name);
    font-weight: 600;
    line-height: 1.25;
    color: var(--ink);
  }

  /* Italic serif at the app's aside size — the voice the greeting, "Casa" and
     every "nothing planned" already speak in. A count is a fact and carries a
     name's weight; permission to leave the cleaning is a whispered suggestion
     and reads wrong in the same size, more like an instruction than an offer. */
  .callout-line.aside {
    font-size: var(--fs-body);
    font-weight: 400;
    font-style: italic;
    color: var(--ink-soft);
  }

  .callout-go {
    grid-column: 2;
    grid-row: 1 / span 2;
    display: grid;
    place-items: center;
    padding-left: 12px;
    color: #A8441F;
  }

  .callout-go svg { width: 18px; height: 18px; display: block; }

  /* ---------- week planner ---------- */

  .day {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 16px;
    border-bottom: 1px solid var(--rule);
  }

  /* An empty day is the whole row as one button. Wider than the 36px "Add" it
     replaces, so the tap target went up rather than down — and the row can
     finally size to its own content, which is one short line. */
  .day-open {
    width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    border-bottom: 1px solid var(--rule);
    padding: 13px 16px;
    cursor: pointer;
    font: inherit;
    color: inherit;
    transition: background .13s ease-out;
  }

  .day-open:hover { background: rgba(var(--glaze-rgb),.34); }
  .day-open:focus-visible { outline: 2px solid var(--dest, var(--tile)); outline-offset: -2px; }
  .day:last-child, .day-open:last-child { border-bottom: 0; }

  .day.is-today { background: rgba(var(--glaze-rgb),.4); }

  .day-name {
    font-family: var(--mono);
    font-size: var(--fs-lead);
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-soft);
    width: 62px;
    flex-shrink: 0;
  }

  /* Colour alone was not enough of a difference: --tile against --ink-soft is
     a hue change at the same weight, on a 10.5px mono label six characters
     wide. The weight is what makes it read as the one that is different. */
  .day.is-today .day-name { color: var(--tile); font-weight: 700; }

  /* Serif, because it is a name. The same dinner reads serif in the library
     below and read sans here — one meal, two faces, on one screen. The rule
     ("serif for names — short-list items, record names, meal names") was
     always right; the planner had quietly opted out of it since it was
     written. */
  .day-meal {
    flex: 1;
    min-width: 0;
    font-family: var(--serif);
    font-size: var(--fs-large);
  }
  .day-meal .none { color: var(--ink-soft); font-style: italic; font-size: var(--fs-large); }

  /* The planner's house marker is day context, not a record's house flag —
     a meal has no house of its own (the plan is keyed by date and the date
     knows the house), and this only renders on days that differ from the
     base house. So it's a deviation note, and it reads in the meta voice
     rather than as a chip. Keeping it inline also means an open day stays
     one line instead of spending a second one on a lone chip. */
  .house-note {
    font-family: var(--mono);
    font-size: var(--fs-lead);
    color: var(--ink-soft);
    white-space: nowrap;
  }
  /* Non-breaking spaces, not plain ones: `nowrap` above collapses a trailing
     space inside generated content, which left the middot welded to the
     house code. */
  .house-note::before { content: "\00a0\00b7\00a0"; }

  /* Effort chips live with the rest of the chip vocabulary — see .chip. */

  /* The picker and the row that opened it are ONE band, and the tint is the
     one the strip already owns: .is-today is glaze at .4 and the picker was
     glaze at .32, so "what colour says this row is open" had an answer
     sitting in the file — the same one, said at the same strength, with the
     rule between them taken out.

     A new colour was the other option and there isn't one to spend. Every
     other hue in the app is committed: --dest is the room, a record's flag is
     its house, ochre and oxblood are attention and are deliberately fixed. */
  .picker {
    padding: 2px 16px 14px;
    background: rgba(var(--glaze-rgb),.4);
    border-bottom: 1px solid var(--rule);
  }

  /* Both row shapes, and it must out-specify .day.is-today. */
  .day.is-picking,
  .day.day-open.is-picking {
    background: rgba(var(--glaze-rgb),.4);
    border-bottom-color: transparent;
  }

  /* And every other row stands down while a picker is open — which in
     practice means today's, the only one that was tinted. Two bands of the
     same value directly against each other read as one band with a hairline
     across it, so the row you are actually editing stopped being findable.
     The name keeps its colour; it is still today. */
  .day.is-unfocused { background: transparent; }

  /* An open day is one whole button, so its "Close" cannot be a button of
     its own — nesting one is invalid markup. It is a word in the row that
     already does the closing, styled to match the quiet button the planned
     rows carry so the two read as the same control. */
  .day-close {
    flex-shrink: 0;
    font-family: var(--ui);
    font-size: var(--fs-body);
    font-weight: 400;
    color: var(--ink-soft);
    padding: 6px 10px;   /* .btn-sm .btn-quiet, so the two line up */
  }

  /* The picker scrolls inside itself rather than pushing the page around. Ten
     meals came to 988px — taller than the phone — wedged into a day row
     partway down a panel that was already three screens tall, so planning
     Tuesday meant losing Tuesday. Capped, the day you tapped stays on screen
     with its choices under it, which is the whole job.

     Not a fixed px: the cap is about how much of the SCREEN a list inside a
     row may take, and that is what vh measures. */
  .picker-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    /* Clear of the kind selector above it: the first choice was sitting on
       that box's border, which read as the two being one control. */
    margin-top: 12px;
    max-height: 44vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  .dinner-form { margin: 10px 0 2px; }

  /* flex-shrink: 0 is the whole of the squashing bug, and min-height was the
     red herring. .picker-list is a column flex container, so every choice is a
     flex item — and a flex item's default flex-shrink is 1. The moment the
     list overflowed its new max-height the browser did exactly what it was
     told and shrank them all to fit, down to the 44px floor min-height set,
     while the name and the chips inside kept their own size and spilled past
     the border.

     It only appeared when the list gained a cap: before that nothing
     overflowed, so nothing shrank. A scroll container made of flex items
     needs this on the items, every time. */
  .pick {
    appearance: none;
    display: block;
    flex-shrink: 0;
    text-align: left;
    background: var(--card);
    border: 1px solid rgba(var(--ink-rgb),.56);
    border-radius: 9px;
    padding: 9px 12px 10px;
    color: var(--ink);
    min-height: 44px;
  }

  /* A name, so it takes the face every other name takes. */
  .pick-name {
    display: block;
    font-family: var(--serif);
    font-size: var(--fs-large);
    line-height: 1.25;
  }

  /* One line, chips and all. This is what took the row from 64px to 44: the
     chips had a .chips row of their own and a name above it. */
  /* 9px rather than 6, and a little air above. At 6 the chips' own borders
     sat close enough to the text beside them that the row read as one crowded
     object rather than as two or three separate facts. */
  .pick-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 9px;
    margin-top: 5px;
  }

  /* Clearing a day is not one of the meals. */
  .pick-clear {
    /* The same 12px .picker-list asks for, for exactly the same reason it
       gives: sitting directly under the kind selector, its border was against
       that box's border and the two read as one control. Moving Clear above
       the list handed the list's clearance to the button and left the button
       with none — the gap moved down a step rather than being added.
       .picker-list keeps its own, so the space below is already there. */
    margin-top: 12px;
    color: var(--ink-soft);
    border-style: dashed;
  }

  /* When it was last actually eaten, in the vocabulary a chore's history
     already speaks — "today", "yesterday", "9 days ago", and nothing at all
     for one never made. It is a fact about the rotation, never a tally about
     her: the app does not say "again?", it says when. */
  .pick-since {
    font-family: var(--mono);
    font-size: var(--fs-lead);
    color: var(--ink-soft);
  }

  .pick:hover { border-color: var(--tile); background: rgba(var(--tile-rgb),.05); }

  /* A section head labels the group below it. It used to be a divider between
     two rows as well, and the divider won: hairlines above and below put it in
     the run of rows rather than over it, and nothing anywhere made a pause. So
     the panel read as one continuous ribbon and the head read as a slightly
     tinted row.

     Three changes, in the order they matter. The pause is space above the head
     — nothing else in the panel creates one, which is the whole of why the
     list had no rhythm. The bottom hairline is gone, and the bottom padding is
     tighter than the top, so the head leans into the rows it names instead of
     being fenced off from them. And the blue glaze band is gone: it was
     foreign in four of the five rooms and read as a smudge rather than as
     structure.

     The 2px rule is the panel's own opening band restated: .panel::before is
     14px of --dest tilework, and a section is a smaller version of the same
     idea. --dest as a border is a fill use and safe at any lightness; --dest
     as *text* is the documented trap this rule used to be sitting in, which is
     what --dest-text is for.

     There is no wash under the head, and that was tried rather than assumed. A
     --dest tint fading downward looked right in the abstract and turned the
     head back into a band on screen — the padded chrome the old one already
     was, in a better colour. Tightened until it was subtle enough not to pad
     the head, it was also too subtle to see, which is the argument for
     removing it. The rule and the space carry the group; the tint was saying
     the same thing a third time.

     The full-bleed 2px --dest rule that first did that job is now a FRIEZE:
     the label, then tilework running out to the edge. Same structure, and it
     gives the azulejo somewhere to live now that it is off the page ground.
     One or two per screen is the ceiling, which holds on its own because a
     frieze marks a change of KIND — her upkeep vs the landlord's, Scheduled
     vs Dinner vs Due. A change of VALUE (one more fact subject, one more
     aisle) takes .group-label below, which carries no tile. Ten subjects
     would otherwise be ten friezes, which is wallpaper again. */
  .section-head {
    display: flex;
    align-items: center;
    gap: 11px;
    font-family: var(--mono);
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--dest-text, var(--dest, var(--house-text)));
    margin-top: 16px;
    padding: 9px 16px 8px;
    white-space: nowrap;
  }

  .section-head::after {
    content: "";
    flex: 1;
    height: 13px;
    min-width: 24px;
    background-image: var(--frieze-pattern);
    opacity: .75;
  }

  /* A change of value, not of kind: same voice, no tilework, and it scales to
     however many subjects the house turns out to have. */
  .group-label {
    font-family: var(--mono);
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--ink-mute);
    padding: 14px 16px 6px;
  }

  /* Scoped to the panel's own first child. Inside a .group every label is
     :first-child by construction, so unscoped this would quietly give all of
     them the reduced pause and flatten the rhythm between groups. */
  .panel > .group-label:first-child { padding-top: 8px; }

  /* The deck: a run of labelled groups, one column until a screen has room
     for more. At phone width this is a plain stack and every measurement
     above it is untouched — the label's own top padding is still what makes
     the pause between one group and the next.

     minmax(0, 1fr) rather than 1fr, because a grid track's default minimum is
     auto: one long unbreakable item would push the track wider than its share
     and the columns would stop being equal. */
  .deck { display: grid; grid-template-columns: minmax(0, 1fr); }
  .group { min-width: 0; }

  /* The pause belongs between groups, so the first head in a container doesn't
     get one — the panel's tile band, the day's week strip or the data screen's
     title bar is already the edge above it. Deliberately unscoped: .panel,
     the data screen and the day's own sections each open with one, and scoping
     this to .panel meant only one of them ever behaved. */
  .section-head:first-child { margin-top: 0; }

  /* A group of rows closes with space, not a line. Without this the last row
     keeps its hairline, so the gap is fenced top and bottom and reads as an
     empty row rather than as a break.

     Rows only. A .note is a band in its own right — tinted, and about the
     panel rather than in it — so its border is still the edge of something
     and stays. Progressive either way: where :has() is missing the hairline
     simply remains, which is what this looked like before. */
  .rec:has(+ .section-head)::after { display: none; }

  /* ---------- shopping ---------- */

  .shop-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 4px 16px;
  }

  .shop-item button.tick {
    appearance: none;
    flex: 1;
    display: flex;
    align-items: center;
    gap: 12px;
    background: transparent;
    border: 0;
    padding: 9px 0;
    text-align: left;
    font-size: var(--fs-large);
    color: var(--ink);
    min-height: 44px;
  }

  /* A ring in the room's colour, like every other check in the app — this was
     the last grey square left over from before the record types had colours. */
  .box {
    width: 22px;
    height: 22px;
    border: 2.2px solid var(--dest, var(--tile));
    border-radius: 50%;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-body);
    /* The tick sits on a filled --dest once checked, which is precisely what
       --dest-ink is for. #fff stays the fallback, since most rooms define no
       --dest-ink and their fills are dark. */
    color: var(--dest-ink, #fff);
  }

  .checked .box { background: var(--dest, var(--tile)); border-color: var(--dest, var(--tile)); }
  .checked .box .ico { color: var(--dest-ink, #fff); }
  .checked .shop-name { text-decoration: line-through; color: var(--ink-mute); }

  .shop-name { flex: 1; }

  /* On the plaster, so no card and no hairline — it was the bottom edge of a
     box the toolbar no longer sits in. Padding matches the add bar's gutter
     rather than a card's. */
  .toolbar {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    padding: 4px 2px 12px;
  }

  /* ---------- house chip ---------- */


  .housechip {
    appearance: none;
    background: color-mix(in srgb, var(--card) 72%, transparent);
    border: 1px solid color-mix(in srgb, var(--house) 38%, transparent);
    color: var(--house-text, var(--house));
    font-family: var(--mono);
    font-size: var(--fs-lead);
    letter-spacing: .06em;
    padding: 6px 10px;
    border-radius: 3px;
    min-height: 32px;
    white-space: nowrap;
    /* It must not squeeze. As a shrinkable flex item it gave up width to the
       date and squashed its own contents instead of taking the new line
       .greet-in's wrap is there to give it — which defeats both rules at
       once. Wrapping is the pressure valve; shrinking is not. */
    flex-shrink: 0;
  }

  .housechip:hover { background: rgba(var(--tile-soft-rgb),.3); }
  .housechip .dot { color: var(--house-light); margin-right: 6px; }

  /* ---------- todos ---------- */

  .todo-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 9px 16px;
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--dest-text, var(--dest, var(--tile)));
    background: rgba(var(--glaze-rgb),.34);
    border-bottom: 1px solid var(--rule);
  }

  .stay {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--rule);
  }

  .stay-when {
    font-family: var(--mono);
    font-size: var(--fs-body);
    color: var(--ink-soft);
    flex: 1;
  }

  .stay-house { font-size: var(--fs-large); }

  .note {
    padding: 12px 16px 14px;
    font-size: var(--fs-body);
    line-height: 1.5;
    color: var(--ink-soft);
    border-bottom: 1px solid var(--rule);
    background: color-mix(in srgb, var(--dest, var(--tile)) 6%, transparent);
  }

  .hidden { display: none !important; }

  /* The lobby belongs to Today. Anywhere else in a stacked layout it pushed the
     panel most of a screen down — three short-list items plus tonight's meal is
     a lot of chrome sitting above content you navigated to on purpose. It
     returns at 1200px, where it's a rail beside the content and costs nothing.

     Today still greets you unconditionally on launch, which is the part that
     matters: dest resets to "today" every load. */
  .lobby { display: none; }
  :root[data-view="today"] .lobby { display: block; }

  /* ---------- week strip ----------
     Seven columns, so roughly 50px each on a phone. Everything here is sized
     for that: the house bar spans the full cell width with no horizontal
     margin, which is what makes consecutive days at one house read as a
     single continuous bar rather than seven chips. */
  /* The strip sits on a wash so the selected column, which is card-coloured,
     lifts out of it and connects to the detail panel below. */
  .weekstrip {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    border-top: 1px solid var(--rule);
    border-bottom: 1px solid var(--rule);
  }

  /* One cell per day, same anatomy as a month cell: number, marks, house.
     This used to be three overlapping grid rows with a transparent button
     laid across them, because the house bar had to span several columns to
     read as one run. The tint carries the run now, so the overlay went with
     it and a day is simply a button. */
  /* It is a <button>, and `color` was never declared — so the day numbers
     have been taking the UA's `buttontext`, which is pure black. On cream
     that passes for ink and nobody noticed for the life of the app; on any
     dark ground it is black on black and the numbers vanish. Declared now,
     which also puts them on the palette in Lisbon where they never were. */
  .wk-cell {
    appearance: none;
    color: var(--ink);
    border: 0;
    border-right: 1px solid var(--rule);
    background: var(--card);
    padding: 10px 2px 8px;
    cursor: pointer;
    min-height: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
  }

  .wk-cell:last-child { border-right: 0; }
  .wk-cell:hover { background: rgba(var(--ink-rgb),.04); }

  /* The selected day is a box rather than a lifted column — the same marker
     the month grid uses, so switching views doesn't change what "selected"
     looks like. */
  .wk-sel { box-shadow: inset 0 0 0 2px var(--dest, var(--tile)); }

  /* Explicitly a column: these are spans inside a span now (the cell is a
     button, so it can't hold divs), and inline children would run the day
     name and its number onto one line. */
  .wk-head {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1px;
    text-align: center;
  }

  .wk-dow {
    font-family: var(--mono);
    font-size: var(--fs-micro);
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-soft);
  }

  .wk-num { font-family: var(--serif); font-size: var(--fs-lead-name); font-weight: 600; line-height: 1.25; }

  /* Today is the cell's ground; "selected" is the outline. Two channels on
     purpose, because a day is very often both at once.

     The bold numeral is deliberate redundancy and costs nothing: a gold
     ground lands within 1.08:1 of the house tints, so on a day you're away
     it would otherwise be separated from its neighbours by hue alone. */
  .wk-today .wk-num,
  .mo-today .mo-num { font-weight: 700; }

  /* The house is the cell's ground now, not a bar across its foot. A bar had
     to be dark to register at 8px, which made seven of them the loudest thing
     on the screen; a tint says the same thing underneath everything else.

     The tint class is only emitted for days at a house you are NOT currently
     at — see weekBody/monthBody — so at most one tint is ever on screen and
     it always reads against plain card. See --cell-sf for why that matters.

     Cell class included so these outrank the plain `background: var(--card)`
     on .wk-cell / .mo-cell whatever order the rules end up in. */
  .wk-cell.wk-house-sf, .mo-cell.mo-house-sf { background: var(--cell-sf); }
  .wk-cell.wk-house-gv, .mo-cell.mo-house-gv { background: var(--cell-gv); }

  /* Today replaces the house tint rather than stacking with it — you know
     where you are today, and the run label still names the house wherever a
     run starts. Same specificity as the tints above, so this has to stay
     BELOW them in source order to win. */
  .wk-cell.wk-today, .mo-cell.mo-today { background: var(--cell-today); }

  /* Selected is the outline: --dest normally, gold when the selected day is
     also today, so the two never compete for one channel. */
  .wk-cell.wk-today.wk-sel,
  .mo-cell.mo-today.mo-sel { box-shadow: inset 0 0 0 2px var(--today-line); }

  /* The redundant channel for the tint above, printed on the first day of
     each run so a stretch at one house is named once rather than seven
     times. Without it the calendar would be relying on hue alone, which the
     markers deliberately never do. */
  .wk-runlabel {
    font-family: var(--mono);
    font-size: var(--fs-micro);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--ink-soft);
    margin-top: auto;
    min-height: 11px;
  }

  /* ---------- month ---------- */

  .cal-modes { display: flex; gap: 4px; flex: none; }

  .cal-mode {
    appearance: none;
    border: 1px solid var(--rule);
    background: transparent;
    color: var(--ink-soft);
    padding: 7px;
    border-radius: 4px;
    cursor: pointer;
    min-height: 0;
    display: grid;
    place-items: center;
  }

  .cal-mode svg { width: 17px; height: 17px; display: block; }

  .cal-mode[aria-current="page"] {
    background: var(--dest, var(--tile));
    border-color: transparent;
    color: var(--dest-ink, #fff);
    font-weight: 600;
  }

  .cal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 11px 12px 10px;
    flex-wrap: wrap;
  }

  .cal-nav { display: flex; align-items: center; gap: 4px; min-width: 0; }

  .cal-back { margin-left: 4px; font-size: var(--fs-body); }

  .cal-title {
    font-family: var(--serif);
    font-size: var(--fs-name);
    font-weight: 600;
    color: var(--ink);
    padding: 0 4px;
    white-space: nowrap;
  }

  .monthgrid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    border-top: 1px solid var(--rule);
  }

  .mo-dow {
    font-family: var(--mono);
    font-size: var(--fs-micro);
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-soft);
    text-align: center;
    padding: 8px 0 6px;
    background: color-mix(in srgb, var(--dest, var(--tile)) 11%, var(--card));
  }

  /* Each cell is its own tap target. The house tint is the ground rather than
     a bar: at this size a 4px stripe under a 2-digit number is noise, but a
     whole tinted cell reads as "you are there" at a glance across the month. */
  .mo-cell {
    appearance: none;
    border: 0;
    border-right: 1px solid var(--rule);
    border-bottom: 1px solid var(--rule);
    background: var(--card);
    padding: 7px 2px 5px;
    min-height: 64px;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
  }

  .mo-cell:nth-child(7n) { border-right: 0; }

  .mo-num { font-family: var(--serif); font-size: var(--fs-large); line-height: 1; color: var(--ink); }

  .mo-out { opacity: .38; }

  /* Today's disc is defined once alongside .wk-today, above. */

  .mo-sel {
    box-shadow: inset 0 0 0 2px var(--dest, var(--tile));
  }

  /* Month draws the same .mk-marks grid the week does — see .mk below. */


  .recipe-link { color: var(--tile); }

  .recipe {
    font-family: var(--mono);
    font-size: var(--fs-body);
    color: var(--ink-soft);
    margin-top: 4px;
  }

  .recipe summary { cursor: pointer; }

  .recipe-body {
    white-space: pre-wrap;
    font-family: var(--ui);
    font-size: var(--fs-body);
    line-height: 1.5;
    color: rgba(var(--ink-rgb),.8);
    margin-top: 6px;
    padding-left: 10px;
    border-left: 2px solid var(--rule);
  }

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

  /* Filler text left, its Add on the right — same shape as a populated row, so
     an empty section reads as somewhere to put something rather than a gap. */
  .day-empty {
    padding: 11px 16px 12px;
    color: var(--ink-soft);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
  }

  /* Colour AND shape. Shape is the redundant channel, so the markers survive
     being 7px, direct sun on a deck, and anyone who doesn't separate the
     hues — none of which colour alone would handle.

     One set for both views. Week and month used to draw different shapes at
     different sizes for the same four facts — a dinner was an open circle in
     one and a diamond in the other — so the legend had to be rebuilt per view
     and neither could teach you the other. */
  .mk-marks {
    display: grid;
    grid-template-columns: repeat(2, 8px);
    grid-auto-rows: 8px;
    gap: 4px;
    justify-content: center;
    align-content: center;
  }

  /* Every mark occupies an identical 8px cell so the 2x2 stays square
     whatever shape sits in it; the shapes size themselves inside. */
  .mk { display: block; width: 8px; height: 8px; box-sizing: border-box; place-self: center; }
  .mk-plan { background: var(--mark-plan); border-radius: 50%; }
  .mk-meal { background: var(--mark-meal); width: 7px; height: 7px; transform: rotate(45deg); }
  /* A checkmark, drawn as two borders on a rotated pseudo-element so it still
     takes its colour from a custom property. */
  .mk-task { position: relative; }
  .mk-task::after {
    content: "";
    position: absolute;
    left: 2px;
    top: -1px;
    width: 4px;
    height: 8px;
    border: solid var(--mark-task);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
  }
  /* Money gets a square: the one shape that isn't round or a line, so a bill
     never gets mistaken for a chore at a glance. */
  .mk-bill { background: var(--mark-bill); width: 7px; height: 7px; border-radius: 1px; }

  /* Ghosted, not hidden. The shape still reads, so an empty day looks like
     four waiting slots rather than a blank. */
  .mk-off.mk-plan,
  .mk-off.mk-meal,
  .mk-off.mk-bill { background: var(--mk-ghost); }
  .mk-off.mk-task::after { border-color: var(--mk-ghost); }

  .wk-legend {
    display: flex;
    gap: 15px;
    flex-wrap: wrap;
    padding: 11px 16px 12px;
    border-top: 1px solid var(--rule);
    font-family: var(--mono);
    font-size: var(--fs-label);
    color: var(--ink-soft);
  }

  .wk-legend span { display: inline-flex; align-items: center; gap: 6px; }

  /* A swatch of the cell tint itself, outlined so a wash this pale still has
     an edge to read against the legend's own ground. */
  .lg-house {
    display: inline-block;
    width: 15px;
    height: 11px;
    border: 1px solid var(--rule);
    border-radius: 2px;
  }
  .lg-house.mo-house-sf { background: var(--cell-sf); }
  .lg-house.mo-house-gv { background: var(--cell-gv); }

  /* Sections within a destination. Sits at the top of the panel rather than
     being a second strip beside the nav, so there's never a question about
     which row you're navigating. */
  /* The panel wears the destination's colour as a band of tilework, the same
     device the lobby card uses. It's the strongest single thing separating one
     room from another at a glance. */
  .panel { position: relative; }

  /* The tile band that used to cap the panel is gone. It was there to give a
     square-cornered box a lid; a rounded card with a shadow needs no lid, and
     the tile now belongs to the masthead and the friezes. The room's colour
     still reaches the panel — through the subnav underline, the frieze labels
     and the section heads. */

  /* Underlined, never pills. A pill row above a list is the filter-chip
     pattern in both Material and iOS, and this app has real filters — the
     Facts house toggle — that need to keep that shape to themselves. Two
     controls one above the other in the same costume, meaning different
     things, is the collision worth avoiding.

     It also fixes what made this the weakest chrome in the app: the tinted
     band and the filled pill were two devices doing one job, and the band was
     a second tinted strip immediately under the masthead. */
  .subnav {
    display: flex;
    gap: 21px;
    padding: 15px 16px 0;
    border-bottom: 1px solid var(--rule);
    background: transparent;
    overflow-x: auto;
  }

  .subnav-item {
    appearance: none;
    border: 0;
    border-bottom: 3px solid transparent;
    background: transparent;
    color: var(--ink-mute);
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: .12em;
    text-transform: uppercase;
    padding: 0 0 9px;
    white-space: nowrap;
    cursor: pointer;
    min-height: 34px;
  }

  .subnav-item:hover { color: var(--ink); }

  /* --dest as a border is a fill use and safe at any lightness; as text it is
     the documented trap, which is what --dest-text is for. */
  .subnav-item[aria-current="page"] {
    background: transparent;
    border-bottom-color: var(--dest, var(--tile));
    color: var(--ink);
    font-weight: 600;
  }

  /* ---------- narrow: bottom bar ----------
     Five destinations, thumb-reachable, and the shape that maps to SwiftUI's
     TabView when this is ported. */
  @media (max-width: 619px) {
    .tabs {
      position: fixed;
      left: 0; right: 0; bottom: 0;
      z-index: 45;
      display: flex;
      gap: 0;
      margin: 0;
      padding: 0;
      overflow: visible;
      border-radius: 0;
      background: var(--ink);
      /* Solid, unlike the wide-screen strip. The bar carries five icon labels
         at 10.5px, and tilework behind type that small competes with it —
         the pattern won on the masthead, where nothing has to be read. */
      background-image: none;
      padding-bottom: env(safe-area-inset-bottom);
      box-shadow: 0 -10px 26px -14px rgba(0,0,0,.55);
    }

    .tab {
      flex: 1 1 0;
      min-width: 0;
      border-radius: 0;
      flex-direction: column;
      gap: 4px;
      text-align: center;
      padding: 9px 3px 9px;
      font-size: var(--fs-label);
      letter-spacing: .01em;
    }

    .tab-tile { width: 32px; height: 32px; border-radius: 9px; }

    /* A wordy item at 20px runs to three lines and pushes the third card —
       and the meal under it — below the fold, which is the one thing the
       short list can't afford to do. It still leads the page; it just doesn't
       have to shout to. */
    .sl-name { font-size: var(--fs-name); }

    /* The bar is dark, so the selected destination brightens rather than
       filling — a full pale tile at this size would swamp the strip. */
    .tab[aria-selected="true"] {
      background: rgba(255,255,255,.10);
      color: var(--glaze);
      box-shadow: inset 0 2px 0 var(--house-light);
    }

    /* Clear the fixed bar, and lift the undo toast above it so the two don't
       stack on top of each other. */
    .wrap { padding-bottom: 112px; }
    .undo { bottom: calc(env(safe-area-inset-bottom) + 84px); }

    /* Interior views used to go edge to edge on a phone, on the grounds that
       "the sliver of ground on each side was just narrowing the content for
       nothing" — with Today exempt, because its cards are meant to float on
       the plaster and that separation is the layout.

       Every view works that way now. The panel is not one box any more; it is
       a stack of cards with friezes between them, and the ground on each side
       is what makes them read as cards rather than as bands. So the exemption
       became the rule and the rule went away.

       10px, not the 14 it went in at. The old rule's reasoning was not wrong,
       only over-applied: on a phone a gutter genuinely is content you don't
       get, and 14 each side plus the card's own 16 put text 30px from the
       screen edge where it used to be 16. Cards need *some* ground to read as
       cards and they don't need much — 10 outside and 14 inside gets the text
       back to 24, which is four percent of the width rather than eight. */
    .wrap { padding-left: 10px; padding-right: 10px; }
    .card > .rec { padding-left: 14px; padding-right: 14px; --pad-x: 14px; }
    .card > .is-firm { padding-left: 11px; }
    .panel > .subnav { padding-left: 4px; padding-right: 4px; }
  }

  /* ---------- wide layouts ----------
     Until now this file had no media queries at all, so a 27" monitor showed a
     660px phone column adrift in the middle of it. Three arrangements of the
     same markup: stacked (narrow), roomier stack (medium), and a three-column
     shell with the lobby as a persistent rail (wide).

     The lobby stays first in source order so narrow screens — and screen
     readers — meet it first. Grid placement moves it right on wide screens
     without touching the DOM. */

  @media (min-width: 620px) {
    .wrap { max-width: 780px; padding: 0 24px 72px; }
    .greet-in { max-width: 780px; padding: 20px 24px 21px; }

    /* auto-fill rather than a column count per breakpoint: the deck appears
       in the panel, which is a different width in each of the three shells,
       and a count would have to be restated in all of them and kept in step.
       The 320px floor is what does the deciding, and it is the phone's own
       measure (355 at 375) less the gap — so a column of the grocery list is
       the column it was designed as, however many of them fit.

       start, not stretch: a two-item aisle beside a seven-item one would
       otherwise grow a card with four inches of nothing under the last row. */
    .deck {
      grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
      column-gap: 14px;
      align-items: start;
    }

    /* A form has a measure, like anything else you read. Stretched to the
       panel it was a 714px-wide box to type "Call the plumber" into, and
       three checkboxes each spanning the full width with a 22px box at the
       far left — the run that was carefully grouped by adjacency read as
       three separate bands again, because nothing that far apart looks like
       a group.

       560 is the pair of fields the .form-row already makes: two columns of
       273 either side of its 14px gap, which is comfortably past the 120px
       basis that once produced fields "too narrow to read what you'd typed".
       It costs nothing below 620, where the panel is narrower than this
       anyway. */
    .form { max-width: 560px; }

    /* The dinner picker is the same trade, and the 44vh cap STAYS. That cap
       is not a phone workaround to be undone on a laptop — it is the rule
       that the day you tapped has to stay on screen with its choices under
       it, and vh is the right unit for it at any size. What changes is how
       much fits inside it: two columns of choices is twice the library
       without the day row moving an inch. Twelve meals came to 795px of
       scrolling inside a 396px window; they are about 330 in two columns,
       so the nested scroller stops existing until the library is genuinely
       large, which is when it was wanted in the first place.

       280px rather than the deck's 320: a choice is a name and one meta
       line, where a grocery aisle carries a check ring and an x as well. */
    .picker-list {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
      align-content: start;
      gap: 6px 10px;
    }
  }

  /* 960–1199: sidebar plus content, and the lobby folds back into the content
     column. Three columns need roughly 1200px before the content gets a fair
     share — at 1000px a 200px nav and a 320px rail leave the panel narrower
     than the rail beside it, which puts the thing you came to read in the
     smallest column. */
  @media (min-width: 960px) {
    .wrap {
      max-width: 1040px;
      /* Breathing room under the masthead. On a phone the panel butting
         straight up against it reads as one surface; at desktop widths, with
         the sidebar starting at the same line, it just looks unfinished. */
      padding: 26px 28px 72px;
      display: grid;
      grid-template-columns: 176px minmax(0, 1fr);
      grid-template-areas:
        "nav lobby"
        "nav panel"
        "footer footer";
      align-items: start;
      column-gap: 28px;
      /* Breathing room under the masthead — the columns butting straight up
         against it read as a rendering fault rather than a layout. */
      padding-top: 26px;
    }

    .greet-in { max-width: 1040px; padding: 22px 28px 23px; }

    /* The ladder itself is what's responsive, rather than one element opting
       out of it. `.today` was the only rule with a literal size left after the
       scale went in, and redefining the rung is how it stays on the scale
       instead of standing beside it. */
    :root { --fs-display: 34px; }

    .lobby  { grid-area: lobby; }
    .tabs   { grid-area: nav;   position: sticky; top: 20px; }
    .panel  { grid-area: panel; }
    .footer { grid-area: footer; }

    /* Folded into the content column, the lobby was three cards stretched to
       the full 780 and stacked — so Tonight's meal name broke over three
       lines beside a Change button with four inches of nothing between them,
       and the to-do list underneath started below the fold.

       The short list is the tall one and the other two are small, so they sit
       beside it rather than under it. Same trade as the deck: the width buys
       another column, never a wider card. The cards keep their own 22px
       bottom margins, which is what spaces cleaning from Tonight — a row-gap
       here would be that distance said twice. */
    /* :root[data-view] and not a bare .lobby, and this is the documented
       trap rather than belt and braces: the lobby's own display is set by
       `:root[data-view="today"] .lobby` at (0,2,0), and a media query adds no
       specificity at all — so a plain `.lobby { display: grid }` here loses,
       silently, and the cards go on stacking. The rule below and the one in
       the 1400 block are deliberately the same weight, so source order is
       what decides between them. */
    :root[data-view="today"] .lobby {
      display: grid;
      /* The small cards take 356 — the rail's width and the phone's, so the
         one card in the lobby with something to fit reads the same in all
         three shells. The short list takes whatever is left, which it can
         use: it is a list of rows, not a thing that has to fit. */
      grid-template-columns: minmax(0, 1fr) 356px;
      grid-template-areas:
        "short cleaning"
        "short tonight";
      align-items: start;
      column-gap: 14px;
    }

    #shortlist { grid-area: short; }
    #cleaning  { grid-area: cleaning; }
    #tonight   { grid-area: tonight; }

    /* The tab strip becomes a sidebar. Same buttons, same data-tab handling —
       only the arrangement changes. */
    .tabs {
      display: flex;
      flex-direction: column;
      gap: 3px;
      padding: 8px;
      border-radius: 4px;
      overflow: visible;
      box-shadow:
        0 1px 2px rgba(var(--ink-rgb),.10),
        0 16px 32px -22px rgba(var(--ink-rgb),.55);
    }

    .tab {
      border-radius: 3px;
      text-align: left;
      padding: 12px 13px;
    }

    /* One pale tile lifted out of the tilework. No coloured edge needed —
       the contrast reversal is the selection. */
    .tab[aria-selected="true"] {
      background: var(--card);
      color: var(--ink);
      box-shadow: 0 1px 3px rgba(0,0,0,.28);
    }

    /* No tab strip above it now, so the panel is a card in its own right. */
    .panel {
      border-top: 1px solid var(--rule);
      border-radius: 3px;
    }

    /* The shortlist's shadow and negative offset were tuned for sitting under
       the masthead; in the rail it just needs to be a card. */
    .shortlist { margin-top: 0; }
  }

  /* 1400+: the three-column shell, and the number is arithmetic rather than a
     round one. It was 1200, and 1200 was where the rail started COSTING the
     panel: measured at the boundary, the panel went 780px wide at 1199 to
     612 at 1200 — a sixth of the reading column handed over at the exact
     moment the screen got bigger. The grocery deck fell from two columns to
     one across that same pixel, which is the sort of thing you only find by
     driving it.

     The rail earns its place where it is free, and its width is not a taste:
     356 is the width the lobby was designed at, which is 375 less the phone's
     two 10px gutters minus a pixel of rounding. At the 300 it used to be, the
     rail was NARROWER than the phone — so the short list's names and Tonight's
     meal wrapped worse on a 27" monitor than in a pocket, which is the whole
     defect in one number.

     Everything else falls out of it: 176 nav + 356 rail + two 28px gaps + the
     wrap's own 28 each side leaves 756 for the panel at 1400, which is 24px
     off the two-column shell's 780 and still comfortably two deck columns
     (654 is the floor). That is the trade — a little reading width for the
     lobby on every screen — and it is worth making only because the 24px
     changes nothing, where the old arrangement's 168 changed everything. */
  @media (min-width: 1400px) {
    .wrap {
      max-width: 1400px;
      grid-template-columns: 176px minmax(0, 1fr) 356px;
      grid-template-areas:
        "nav panel lobby"
        "footer footer footer";
    }

    .greet-in { max-width: 1400px; }

    /* Wide enough for the rail, so the lobby comes back on every destination —
       and display:block puts back the single column the folded layout above
       arranged into two. Both selectors, at the same weight as the folded
       rule, so this one wins on source order rather than by accident. */
    .lobby,
    :root[data-view="today"] .lobby { display: block; position: sticky; top: 20px; }
  }

  /* ---------- the Front Door ---------- */

  /* Full-bleed, and not a card. A card separates content from other content,
     and this screen has none — it is the only thing on it. It had been a
     white box centred on a patterned ground, which was the right answer while
     the ground was patterned and became a box floating on nothing once the
     motif came off.

     What replaces it: the azulejo at full strength across the top, fading
     down into the plaster, with the wordmark sitting in the fade. The band
     takes --glaze and --masthead-pattern, so arriving in Guerneville opens a
     green door — which is the one moment in the day the app gets to say where
     you are before you have read a word. */
  .frontdoor {
    position: fixed;
    inset: 0;
    z-index: 60;
    padding: 0 0 26px;
    overflow-y: auto;
    background: var(--plaster);
  }

  .frontdoor::before {
    content: "";
    display: block;
    height: 190px;
    background: var(--glaze);
    background-image: var(--masthead-pattern);
    /* Fades rather than ending on a line: an edge here would read as the top
       of a card, which is the thing this stopped being. */
    -webkit-mask-image: linear-gradient(to bottom, #000 34%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 34%, transparent 100%);
  }

  /* Pulled up into the band so the wordmark sits in the fade rather than
     under it. -86 of a 190px band puts it around 104px down, which clears the
     notch on a real device with room to spare. */
  .fd-in {
    position: relative;
    width: 100%;
    max-width: 440px;
    margin: -86px auto 0;
    padding: 0 22px;
  }

  /* The wordmark, at the size it deserves when it only appears once. */
  /* The one bold thing above the options, and the only place the app says its
     own name. Big enough to be the reason the band is there. */
  /* A <button> rather than a <p>, because it is the way into the skin — so
     it needs the element reset back to looking like type. It keeps its own
     press treatment from the global rule; nothing else about the Front Door
     changes, and getting past it still takes one tap. */
  .fd-brand {
    appearance: none;
    display: block;
    background: none;
    border: 0;
    padding: 0;
    text-align: left;
    min-height: 0;
    cursor: pointer;
    font-family: var(--serif);
    font-size: var(--fs-brand);
    font-weight: 600;
    letter-spacing: -.02em;
    line-height: 1;
    color: var(--tile);
    margin: 0;
  }

  /* A short brass rule under the wordmark, echoing the gold hairline that
     runs under the masthead band on every interior screen — the same join,
     said once on the way in. */
  .fd-brand::after {
    content: "";
    display: block;
    width: 58px;
    height: 3px;
    background: var(--latao);
    margin: 11px 0 24px;
  }

  .fd-brand em { font-style: italic; color: var(--ochre); }

  .fd-day {
    font-family: var(--mono);
    font-size: var(--fs-label);
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--ink-mute);
  }

  /* Not bold. Exactly one element above the options carries weight and it is
     the wordmark — at 36px against 22px the hierarchy is already made, and
     bolding this too made the two read as peers regardless of size. */
  .fd-q {
    font-family: var(--serif);
    font-weight: 400;
    font-size: var(--fs-title);
    line-height: 1.25;
    margin: 6px 0 18px;
    color: var(--ink);
  }

  .fd-q b { font-weight: 400; color: var(--ink-mute); font-size: var(--fs-name); }

  .fd-levels { display: flex; flex-direction: column; gap: 7px; }

  /* All five identical. The order is a scale because the answer is one, but
     grading them by colour would rank her day back at her — and the warm
     end of any ramp is an attention colour, which is reserved and means
     something else. The word is the whole signal. */
  /* Five identical rows. The order is a scale because the answer is one, but
     grading them by colour would rank her day back at her — and the warm end
     of any ramp is an attention colour, which is reserved and means something
     else. The word is the whole signal.

     17px and ~46px tall so all five, the question and the way out fit one
     screen without scrolling. This is what she sees first on a bad morning;
     having to scroll to answer "how's today?" would be its own answer. */
  .fd-level {
    display: block;
    width: 100%;
    text-align: left;
    /* Sans, against the serif wordmark and question above them. The
       reconciled mockup set no family here at all, so the options inherited
       the UI face and the contrast was the point — folding it in gave them
       the serif and quietly lost that. The container was set to --ui to
       correct it, which did nothing: this rule wins on the buttons. */
    font-family: var(--ui);
    font-size: var(--fs-name);
    color: var(--ink);
    background: var(--card);
    border: 1px solid rgba(var(--ink-rgb),.56);
    border-radius: 12px;
    padding: 13px 16px;
    cursor: pointer;
    transition: background .13s ease-out, border-color .13s ease-out;
  }

  .fd-level:hover { background: rgba(var(--ink-rgb),.04); }

  /* Composited over --card rather than laid on at 9% alpha. The row's own
     background is card; a translucent fill *replaces* it, so the tint was
     landing on the door's plaster instead and coming out a muddy beige that
     read as disabled rather than chosen. */
  .fd-level[aria-pressed="true"] {
    border-color: var(--tile);
    background: color-mix(in srgb, var(--tile) 10%, var(--card));
  }

  /* No rule above it. That hairline was the foot of a card; there is no card
     now, and a line drawn across bare plaster is a line about nothing. */
  .fd-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 22px;
  }

  .fd-note { font-size: var(--fs-body); color: var(--ink-mute); }

  /* Sits where the explanatory note sits on a first pass. The explanation
     matters on the way in; on the way back, an action does. */
  .fd-clear { font-size: var(--fs-body); }

  /* The lobby's quiet way back in. A statement of what was answered, never a
     comment on it, and no history behind it to comment on. */
  .fd-standing {
    display: block;
    width: 100%;
    text-align: left;
    font-family: var(--ui);
    font-size: var(--fs-body);
    color: var(--ink-mute);
    background: none;
    border: 0;
    border-top: 1px solid var(--rule);
    padding: 10px 2px 0;
    margin-top: 12px;
    cursor: pointer;
  }

  .fd-standing:hover { color: var(--ink); }

  @media (prefers-reduced-motion: no-preference) {
    .frontdoor { animation: fd-in .2s ease-out; }
    @keyframes fd-in {
      from { opacity: 0; }
      to   { opacity: 1; }
    }
    .undo { animation: rise .22s ease-out; }
    @keyframes rise {
      from { opacity: 0; transform: translate(-50%, 10px); }
      to   { opacity: 1; transform: translate(-50%, 0); }
    }
  }
