:root{
    --ai-indigo:#1b2a4a;
    --ai-indigo-deep:#0e1830;
    --ai-indigo-soft:#243a63;
    --washi:#f2ebdd;
    --washi-dim:#e4d9c2;
    --lantern:#e8963c;
    --lantern-bright:#f7c877;
    --sumi:#241f1c;
    --momiji:#c2543a;
    --moss:#7ea184;
    --text-dim:#c3ccdf;
    --radius-card:14px;
    /* What stands outside the title screen on a phone, and therefore what its
       height has to leave room for: the body's 8px top and 18px bottom
       padding, the credit footer's 18px margin, and the footer's own line.
       Measured rather than guessed - the old figure covered the padding only,
       which is why the credit line was sliced in half at every phone width. */
    --title-chrome:60px;
  }

  *{box-sizing:border-box;}
  html,body{
    background:var(--ai-indigo-deep);
    color:var(--washi);
    font-family:'Zen Maru Gothic',"Hiragino Maru Gothic ProN","Yu Gothic",sans-serif;
    min-height:100%;
  }

  body{
    margin:0;
    padding:12px 16px 24px;
    display:flex;
    justify-content:center;
    background:
      radial-gradient(560px 360px at 18% 8%, rgba(232,150,60,0.16), transparent 60%),
      radial-gradient(480px 320px at 86% 78%, rgba(232,150,60,0.10), transparent 60%),
      radial-gradient(1200px 800px at 50% -10%, var(--ai-indigo) 0%, var(--ai-indigo-deep) 55%, #080f21 100%);
    position:relative;
    overflow-x:hidden;
  }

  .glow-orb{
    position:fixed;
    border-radius:50%;
    filter:blur(2px);
    background:radial-gradient(circle, rgba(247,200,119,0.85) 0%, rgba(232,150,60,0.35) 45%, transparent 72%);
    opacity:0.55;
    pointer-events:none;
    animation:drift 9s ease-in-out infinite;
  }
  .glow-orb.a{width:120px;height:120px;top:6%;left:8%;animation-delay:0s;}
  .glow-orb.b{width:90px;height:90px;top:60%;left:88%;animation-delay:2.4s;}
  .glow-orb.c{width:70px;height:70px;top:80%;left:12%;animation-delay:4.8s;}
  @keyframes drift{
    0%,100%{transform:translateY(0) translateX(0);}
    50%{transform:translateY(-14px) translateX(8px);}
  }

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

  .stage{
    width:100%;
    max-width:1100px;
    position:relative;
    z-index:1;
  }

  .frame{
    background:linear-gradient(180deg, var(--washi) 0%, var(--washi-dim) 100%);
    color:var(--sumi);
    border-radius:var(--radius-card);
    box-shadow:
      0 1px 0 rgba(255,255,255,0.5) inset,
      0 24px 60px rgba(3,7,20,0.55),
      0 0 0 1px rgba(36,42,74,0.08);
    padding:22px 22px 26px;
    position:relative;
  }
  .frame::before{
    content:"";
    position:absolute; inset:8px;
    border:1px solid rgba(27,42,74,0.18);
    border-radius:9px;
    pointer-events:none;
  }

  h1,h2,h3{margin:0; text-wrap:balance;}
  .jp{font-family:'Shippori Mincho', serif;}

  /* ---------- title screen ---------- */
  #screen-title{width:100%;max-width:900px;margin-inline:auto}
  /* showMap() reveals this with an inline display:flex - the stylesheet
     hides it below - so the direction is set here to keep both in one place. */
  #screen-map{width:100%;max-width:min(1100px,calc((100vh - 220px)*1.5));margin-inline:auto;flex-direction:column}
  /* The title screen is the painting, lit.
   *
   * Every colour below is sampled from the artwork rather than picked next to
   * it: the sky is #001140, the lantern paper #f98e2c, the moon #ddc8bb, the
   * bridge #66130d. A veil mixed from a different black - the old one was a
   * cold rgba(6,13,28) - reads as a grey sheet laid over a blue night, which
   * is what made the screen look like UI on top of art instead of one scene.
   *
   * What was here before painted rgba(6,13,28,.92) across the left 42% to
   * clear a column for the text. That column is where the painting keeps the
   * big paper lantern, the sakura branch and the stone lantern - the three
   * things that say what this game is. The text moved down onto the wet
   * stones at the bottom left instead, which are dark and almost featureless,
   * so it needs no slab to be read against, and the whole upper frame is left
   * to the art. */
  #screen-title.title-scene{
    --night:#001140;
    --night-deep:#000a22;
    --flame:#f98e2c;
    --flame-pale:#ffdca6;
    --moon:#ddc8bb;
    min-height:min(640px,calc(100svh - 36px));
    overflow:hidden;
    isolation:isolate;
    padding:clamp(26px,5vw,54px);
    display:flex;
    flex-direction:column;
    justify-content:flex-end;
    align-items:flex-start;
    gap:clamp(18px,3.4vh,30px);
    text-align:left;
    color:#fff6df;
    background:
      /* Night pooling in the bottom left corner, where the text stands - the
         shape a lantern's light leaves behind rather than a straight edge. */
      radial-gradient(115% 78% at 4% 104%,rgba(0,10,34,.94) 0%,rgba(0,10,34,.72) 34%,rgba(0,10,34,.28) 58%,rgba(0,17,64,0) 76%),
      linear-gradient(0deg,rgba(0,10,34,.78) 0%,rgba(0,10,34,.24) 26%,rgba(0,17,64,0) 52%),
      /* A vignette closes the frame without touching the middle of the scene. */
      radial-gradient(140% 120% at 50% 42%,rgba(0,17,64,0) 46%,rgba(0,10,34,.42) 100%),
      url("assets/title/lantern-alley-title-v1.webp") center/cover no-repeat;
    box-shadow:0 28px 70px rgba(3,7,20,.62),0 0 0 1px rgba(247,200,119,.18);
  }
  #screen-title.title-scene::before{border-color:rgba(247,207,137,.36);z-index:5}
  /* The warmth the alley's own lanterns throw back onto the near stones. */
  .title-scene-shade{position:absolute;inset:0;z-index:-1;pointer-events:none;
    background:radial-gradient(58% 40% at 76% 62%,rgba(249,142,44,.14),transparent 68%)}

  .title-copy{position:relative;z-index:2;max-width:min(560px,92%)}
  /* Lit, not shadowed. The wordmark takes its glow from the lanterns around
     it - two warm blooms and one tight dark edge for legibility - where a
     black drop shadow would have lit it from a source the painting has not
     got. */
  #screen-title.title-scene h1{
    font-family:'Shippori Mincho', serif;
    font-size:clamp(2.5rem,7.4vw,4.4rem);
    font-weight:800;
    line-height:1.02;
    color:#ffeccd;
    letter-spacing:.13em;
    text-indent:.13em;
    text-shadow:0 0 30px rgba(249,142,44,.34),0 0 72px rgba(249,142,44,.18),0 2px 12px rgba(0,6,20,.92);
  }
  .title-english{
    margin:17px 0 0;
    color:var(--moon);
    font-family:'Shippori Mincho',serif;
    font-size:clamp(.76rem,1.5vw,.88rem);
    font-weight:500;
    letter-spacing:.34em;
    text-indent:.34em;
    text-shadow:0 2px 10px rgba(0,6,20,.8);
  }
  .title-lede{
    margin:14px 0 0;
    max-width:34ch;
    color:rgba(255,240,214,.76);
    font-size:clamp(.8rem,1.6vw,.92rem);
    font-weight:500;
    line-height:1.55;
    text-shadow:0 2px 12px rgba(0,6,20,.9);
  }

  /* Kon stands on the stones at the mouth of the alley. Graded down to the
     night the painting is lit by - she arrived at full daylight brightness -
     with a warm edge from the lantern side, and an ellipse under her feet so
     she has ground to stand on. The ellipse replaces a pseudo-element that
     used to draw a mouth onto the mouthless pose. */
  .title-kon{
    position:absolute;right:2%;bottom:6%;z-index:1;
    width:clamp(128px,19%,188px);
    filter:brightness(.84) saturate(.9) drop-shadow(8px -2px 16px rgba(249,142,44,.26)) drop-shadow(0 16px 18px rgba(0,6,20,.55));
    pointer-events:none;user-select:none;
  }
  .title-kon img{display:block;width:100%;height:auto}
  .title-kon::after{
    content:"";position:absolute;left:50%;bottom:-2%;
    width:62%;height:7%;
    background:radial-gradient(closest-side,rgba(0,6,20,.62),rgba(0,6,20,0));
    transform:translateX(-50%);
  }

  .title-entry-panel{position:relative;z-index:3;display:flex;flex-direction:column;align-items:flex-start;gap:12px;max-width:430px}
  .build-stamp{margin:0;order:-1;font-size:.68rem;font-weight:700;letter-spacing:.08em;color:rgba(247,223,171,.6)}
  /* Shown beside the verdict, which is the one row a phone is guaranteed to
     have on screen when an answer lands. */
  .feedback-streak{display:inline-flex;align-items:center;gap:4px;margin-left:8px;padding:2px 9px;border-radius:999px;background:linear-gradient(180deg,#5a2f12,#3a1b09);border:1.5px solid #ffb43d;color:#ffd970;font-size:.8rem;font-weight:900;white-space:nowrap;vertical-align:middle;animation:streak-pop .34s cubic-bezier(.34,1.56,.64,1)}
  .feedback-streak b{color:#7ee07e}
  .progress-note{
    max-width:38ch;
    padding:7px 11px;
    border:1px solid rgba(246,203,126,.4);
    border-radius:999px;
    background:rgba(0,10,34,.76);
    color:#f2dfbc;
    font-size:.76rem;
    font-weight:700;
    backdrop-filter:blur(5px);
  }
  .title-scene .title-actions{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
  /* The one bright thing on the screen, and the thing the screen is for: a
     lit paper lantern, the same washi and flame as the ones hanging in the
     painting, throwing its own light onto the stones under it. The glossy
     orange pill it replaces was the only object here that could have come
     from any other app. */
  .title-scene .btn-primary{
    min-width:184px;
    padding:15px 30px;
    border:1px solid rgba(255,222,170,.72);
    border-radius:7px;
    background:linear-gradient(180deg,#ffe7bd 0%,#ffcf8d 46%,#f6ab55 100%);
    color:#3a1a06;
    font-family:'Shippori Mincho',serif;
    font-weight:800;
    letter-spacing:.18em;
    text-indent:.18em;
    box-shadow:
      0 0 0 1px rgba(58,26,6,.22),
      0 0 30px rgba(249,142,44,.42),
      0 0 78px rgba(249,142,44,.26),
      0 14px 30px rgba(0,6,20,.44),
      inset 0 1px rgba(255,255,255,.6);
    transition:box-shadow .22s ease,transform .22s ease;
  }
  .title-scene .btn-primary:hover,.title-scene .btn-primary:focus-visible{
    transform:translateY(-1px);
    box-shadow:
      0 0 0 1px rgba(58,26,6,.22),
      0 0 38px rgba(249,142,44,.56),
      0 0 96px rgba(249,142,44,.34),
      0 16px 34px rgba(0,6,20,.46),
      inset 0 1px rgba(255,255,255,.7);
  }
  /* Everything that is not the way in stays out of the light. */
  .title-scene .btn-ghost{
    padding:8px 2px;
    border:0;border-bottom:1px solid rgba(221,200,187,.34);
    border-radius:0;
    background:none;
    color:rgba(255,240,214,.72);
    font-size:.84rem;
    font-weight:600;
    letter-spacing:.06em;
    box-shadow:none;
  }
  .title-scene .btn-ghost:hover,.title-scene .btn-ghost:focus-visible{
    color:#ffeccd;border-bottom-color:rgba(255,220,166,.8);background:none;
  }

  .character-scene{min-height:min(760px,calc(100svh - 24px));display:grid;place-items:end center;padding:18px;background:linear-gradient(rgba(6,12,25,.08),rgba(6,12,25,.52)),url("assets/entrance/wooden-gate-v1.webp") center/cover;color:#fff0cf}
  .character-panel{width:min(880px,100%);padding:14px 18px 16px;border:2px solid #8c562d;border-radius:16px;background:rgba(49,27,18,.78);backdrop-filter:blur(9px) saturate(115%);box-shadow:inset 0 1px rgba(255,226,167,.25),0 18px 45px rgba(0,0,0,.46)}
  .character-guide{display:flex;align-items:center;justify-content:center;gap:12px;margin-bottom:8px;text-align:left}
  .character-guide img{width:76px;height:76px;object-fit:contain;filter:drop-shadow(0 6px 5px rgba(0,0,0,.35))}
  /* Still worn by the character screen, which is where this label now lives
     alone - the title screen used to carry one too. */
  .title-kicker{margin:0 0 8px;color:#f1cd8b;font-size:.72rem;font-weight:800;letter-spacing:.18em}
  /* The gloss on the navigation layer.
     A learner at 0% met 理解度, 覚えた言葉, 未訪問 and 月見宿へ行く with no
     support, on the screens where they were deciding where to go - while the
     lesson screens, where reading the Japanese is the whole exercise, spoke
     to them in English. This is the support put back on the right side of
     that line: quiet, secondary, and never on the content itself. */
  .screen-gloss{margin:6px 0 0;color:rgba(255,240,214,.66);font-size:.74rem;font-weight:500;line-height:1.45}
  /* On the map this line is the instruction rather than a gloss on one, since
     the Japanese sentence above it was removed as a duplicate. It carries the
     contrast that job needs. */
  .map-heading .screen-gloss{color:rgba(255,240,214,.84)}
  .metric-gloss{display:block;margin-top:1px;color:rgba(255,240,214,.55);font-size:.58rem;font-weight:600;letter-spacing:.04em;text-transform:none}
  .map-detail .metric-gloss,.map-detail-progress-label .metric-gloss{color:rgba(74,52,35,.62)}
  .character-guide .title-kicker{margin:0;color:#f1bd70}
  .character-panel h2{margin:2px 0 0;font-family:'Shippori Mincho',serif;font-size:clamp(1.2rem,3vw,1.75rem)}
  .character-options{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
  .character-option{display:flex;flex-direction:column;align-items:center;min-height:290px;padding:6px;border:2px solid rgba(219,157,86,.72);border-radius:14px;background:rgba(24,18,18,.38);color:#fff0cf;font:800 1rem 'Zen Maru Gothic',sans-serif;cursor:pointer;box-shadow:0 5px 0 rgba(25,14,10,.72);transition:transform .16s ease,border-color .16s ease,background .16s ease}
  .character-option:hover,.character-option:focus-visible{transform:translateY(-3px);border-color:#ffd27a;background:rgba(82,45,27,.68);outline:3px solid #f2ad55;outline-offset:2px}
  .character-preview{display:block;width:min(150px,100%);aspect-ratio:1/2;margin:auto auto 3px;background-repeat:no-repeat;background-size:400% 100%;background-position:0 center;filter:drop-shadow(0 8px 5px rgba(0,0,0,.38))}
  .character-preview-man{background-image:url("assets/entrance/player-actions-kimono-man-v2.webp")}
  .character-preview-woman{background-image:url("assets/entrance/player-actions-kimono-woman-v2.webp")}
  @media(max-width:560px){.character-scene{padding:8px}.character-panel{padding:10px}.character-guide{gap:7px}.character-guide img{width:54px;height:54px}.character-options{gap:7px}.character-option{min-height:232px;padding:4px}.character-preview{width:108px}}
  [hidden]{display:none !important}

  @media(max-width:620px){
    /* The 24px this used to subtract covered the body's padding and nothing
       else, so the title screen was taller than the space left for it and
       the credit line under it was cut in half at every phone size. The
       subtraction is the whole of what sits outside the frame: PHONE_CHROME
       - see the comment on the custom property. */
    /* A phone crops the painting to its middle, which is where the alley
       runs: the stairs, the tea-house lanterns and the wet stones stay in
       frame, and the text still stands on the dark stones at the bottom. */
    #screen-title.title-scene{min-height:calc(100svh - var(--title-chrome));padding:34px 20px 20px;background-position:58% center;gap:0;justify-content:flex-start}
    /* Never let the title break. At 320px it split after 言葉, which reads as
       two words rather than one name; the clamp is sized so five characters
       and their tracking fit the narrowest phone in one line. */
    #screen-title.title-scene h1{font-size:clamp(1.95rem,11.4vw,3.4rem);white-space:nowrap}
    .title-english{letter-spacing:.34em;text-indent:.34em}
    .title-lede{margin-top:11px;max-width:26ch}
    .title-kicker{font-size:.62rem}
    /* Kon keeps the far corner of the stones. She is small here because the
       button beside her is the errand and she is the welcome, and because
       the two of them share one line of ground; bottom:11% clears the
       feedback pill fixed 14px off the bottom right. */
    .title-kon{right:-2%;bottom:13%;top:auto;width:min(28vw,120px);z-index:0;opacity:.9}
    .title-entry-panel{width:100%;margin-top:auto;padding-top:18px}
    .title-scene .title-actions{width:100%;align-items:flex-start;flex-direction:column}
    .title-scene .btn-primary{width:min(78%,280px);padding:14px 22px}
    .title-utility{margin-top:8px}
  }
  @media(prefers-reduced-motion:reduce){.map-kon-marker{transition:none}.map-kon-marker.is-traveling{transform:translate(-50%,-108%)}}

  .btn{
    font-family:'Zen Maru Gothic', sans-serif;
    font-weight:700;
    font-size:1rem;
    border:none;
    cursor:pointer;
    border-radius:999px;
    padding:13px 26px;
    transition:transform 0.12s ease, box-shadow 0.12s ease, filter 0.12s ease;
  }
  .btn:focus-visible{outline:3px solid var(--lantern-bright); outline-offset:2px;}
  .btn-primary{
    background:linear-gradient(180deg, var(--lantern-bright), var(--lantern));
    color:#3a2308;
    box-shadow:0 8px 18px rgba(232,150,60,0.38), 0 1px 0 rgba(255,255,255,0.4) inset;
  }
  .btn-primary:hover{transform:translateY(-1px); filter:brightness(1.04);}
  .btn-primary:disabled{opacity:0.5; cursor:not-allowed; transform:none; filter:none;}
  .btn-ghost{
    background:transparent;
    color:var(--ai-indigo);
    border:1.5px solid rgba(27,42,74,0.3);
    padding:11px 20px;
  }
  .btn-ghost:hover{background:rgba(27,42,74,0.06);}
  .btn-small{padding:8px 16px; font-size:0.85rem;}
  .title-actions{display:flex; flex-direction:column; align-items:center; gap:10px; margin-top:20px;}

  /* ---------- map screen ---------- */
  #screen-map{display:none;}
  .map-frame{padding:0;overflow:hidden;background:#151423;border:1px solid #7f654e}
  .map-frame::before{display:none}
  .map-top{
    display:flex;align-items:center;justify-content:space-between;
    min-height:54px;padding:10px 18px;gap:12px;background:#151423;color:#f7e8cc;border-bottom:1px solid #70573f;
  }
  .map-heading{display:flex; flex-direction:column;}
  .map-heading h2{
    font-family:'Shippori Mincho',serif;font-size:1.2rem;color:#f7e8cc;letter-spacing:.08em;
  }
  .map-heading span{font-size:.72rem;color:#cdbd9e}
  .map-goal-note{margin:3px 0 0;max-width:46ch;color:#e7d3a6;font-size:.7rem;line-height:1.4}
  /* Wraps at every width, not only on a phone: the row holds two buttons now
     as well as the lantern count. */
  .map-progress{display:flex;flex-wrap:wrap;align-items:center;gap:8px;color:#e4d2b0;font-size:.78rem;font-weight:700;white-space:nowrap;flex-shrink:0}
  .map-progress-lantern{width:15px;height:20px;border:2px solid #6a3f24;border-radius:7px;background:#efb84d;box-shadow:0 0 12px rgba(255,199,90,.85)}
  /* The buttons in this row sit on the map's dark header, and .btn-ghost is
     drawn for a light one: var(--ai-indigo) text inside a 30%-opacity indigo
     border. まちがえた言葉 was navy on near-black and could not be read at
     all - the one button on the screen that tells a learner they have work
     owed. It takes the warm outline the row's other button already had. */
  .map-progress .btn-ghost{
    border-color:rgba(247,215,159,.5);
    color:#ffeccd;
    background:rgba(9,18,34,.5);
  }
  .map-progress .btn-ghost:hover,.map-progress .btn-ghost:focus-visible{
    border-color:rgba(255,220,166,.85);
    background:rgba(20,32,54,.72);
  }

  .map-scene{position:relative;width:100%;aspect-ratio:3/2;overflow:hidden;background-image:linear-gradient(0deg,rgba(14,15,31,.16),rgba(14,15,31,.03)),url("assets/map/lantern-alley-map-v1.jpg");background-size:cover;background-position:center;isolation:isolate}
  .map-scene::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;box-shadow:inset 0 0 46px rgba(5,7,18,.56)}
  .map-stage-route{position:absolute;inset:0;z-index:1;width:100%;height:100%;overflow:visible;pointer-events:none}
  #map-stage-route-line{fill:none;stroke:#f0c879;stroke-width:.65;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:1.7 2.1;opacity:.46}
  #map-home-route-line{fill:none;stroke:#f0c879;stroke-width:.75;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:1.5 2.2;opacity:.68}
  .map-kon-marker{position:absolute;z-index:3;width:30px;height:30px;display:grid;place-items:center;transform:translate(-50%,-108%);border:2px solid rgba(255,218,145,.9);border-radius:50%;background:radial-gradient(circle at 50% 38%,rgba(255,224,160,.82),rgba(132,69,36,.7) 72%);box-shadow:0 2px 7px rgba(0,0,0,.58),0 0 10px rgba(255,190,82,.24);pointer-events:none;transition:left .52s cubic-bezier(.22,1,.36,1),top .52s cubic-bezier(.22,1,.36,1),transform .18s ease}
  .map-kon-marker img{width:26px;height:26px;object-fit:contain;filter:drop-shadow(0 2px 2px rgba(27,15,10,.62))}
  .map-kon-marker.is-traveling{transform:translate(-50%,-108%) scale(1.12);box-shadow:0 2px 7px rgba(0,0,0,.58),0 0 16px rgba(255,190,82,.5)}
  #map-destinations{position:absolute;inset:0;z-index:2}
  .map-destination{position:absolute;transform:translate(-50%,-50%);display:flex;flex-direction:column;align-items:center;justify-content:center;min-width:44px;min-height:44px;padding:0;border:0;background:transparent;color:#fff9e9;cursor:pointer;font-family:'Zen Maru Gothic',sans-serif;filter:drop-shadow(0 4px 6px rgba(0,0,0,.72))}
  .map-home-icon{width:46px;height:46px;object-fit:contain;margin-bottom:2px;filter:drop-shadow(0 3px 3px rgba(16,10,11,.7));transition:transform .16s ease,filter .16s ease}
  .map-destination-label{margin:0;padding:4px 8px;border:1px solid rgba(216,184,121,.86);border-radius:7px;background:rgba(33,24,23,.88);font-family:'Shippori Mincho',serif;font-size:.78rem;font-weight:800;line-height:1.2;letter-spacing:.03em;white-space:nowrap;transition:transform .16s ease,border-color .16s ease,background .16s ease,box-shadow .16s ease}
  .map-destination.is-home .map-destination-label{margin-top:2px}
  .map-destination:hover .map-home-icon,.map-destination[aria-pressed="true"] .map-home-icon{transform:scale(1.09);filter:drop-shadow(0 3px 5px rgba(255,191,86,.42))}
  .map-destination:hover .map-destination-label,.map-destination[aria-pressed="true"] .map-destination-label{transform:scale(1.06);border-color:#f2d28c;background:rgba(62,38,27,.94)}
  .map-destination:focus-visible{outline:3px solid var(--lantern-bright);outline-offset:4px;border-radius:8px}
  .map-destination.state-completed .map-destination-label{border-color:#b9d69e;background:rgba(40,57,41,.9);color:#eff8d5}
  .map-destination.is-next .map-destination-label{border-color:#ffd27a;background:rgba(86,49,28,.94);color:#fff3d0;box-shadow:0 0 0 2px rgba(255,210,122,.14),0 0 12px rgba(255,194,91,.38)}
  .map-destination.state-preparing .map-destination-label{opacity:.72;filter:saturate(.45)}

  .map-detail{display:grid;grid-template-columns:78px minmax(0,1fr) auto;align-items:center;gap:15px;min-height:132px;padding:14px 18px;background:#fbf5e9;border-top:7px solid #5b3927;box-shadow:inset 0 5px #9c6945}
  .map-kon{width:74px;height:74px;object-fit:contain;filter:drop-shadow(0 6px 6px rgba(109,81,58,.28))}
  .map-detail-copy{min-width:0}
  .map-detail-status{display:inline-block;margin-bottom:3px;color:#a24c31;font-size:.68rem;font-weight:800;letter-spacing:.12em}
  .map-detail-name{font-family:'Shippori Mincho',serif;font-size:1.3rem;line-height:1.2;color:#2c2420}
  .map-detail-story{margin:5px 0 3px;font-family:'Shippori Mincho',serif;font-size:.88rem;line-height:1.5;color:#4b3c32}
  .map-detail-focus{margin:0;color:#786c61;font-size:.72rem;line-height:1.4}
  .map-detail-action{min-width:142px;justify-content:center;padding:11px 17px;font-size:.85rem}
  /* Second action on the card, and deliberately the quieter one: going in is
     the thing to do, and the check is the thing still owed. */
  .map-detail-check{min-width:142px;justify-content:center;padding:10px 15px;font-size:.8rem;
    border-color:rgba(162,76,49,.5);color:#8a3f28;background:rgba(162,76,49,.08)}
  .map-detail-check:hover,.map-detail-check:focus-visible{border-color:#a24c31;background:rgba(162,76,49,.16)}
  /* Full width on its own row in both the phone's two-column grid and the
     desktop three-column one, so it reads as a rule under the description
     rather than a third thing competing beside it. */
  .map-detail-progress{grid-column:1/-1;display:grid;gap:5px}
  .map-detail-progress-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
  .map-detail-progress-label{color:#7a5a3d;font-size:.7rem;font-weight:800;letter-spacing:.1em}
  .map-detail-progress-value{color:#8a4a2c;font-size:.9rem;font-weight:900;font-variant-numeric:tabular-nums}
  .map-detail-progress-track{height:8px;border-radius:99px;background:rgba(93,60,38,.16);overflow:hidden}
  .map-detail-progress-fill{display:block;height:100%;width:0;border-radius:99px;
    background:linear-gradient(90deg,#e8963c,#f7c877);transition:width .45s cubic-bezier(.22,1,.36,1)}
  .map-detail-progress-words{margin:0;color:#786c61;font-size:.72rem;line-height:1.4}
  @media(prefers-reduced-motion:reduce){.map-detail-progress-fill{transition:none}}

  @media(max-width:700px){
    #screen-map{max-width:680px}
    /* The header is a row of a title block and a stats row, and it did not
       wrap. On a phone the stats held their width and the title was squeezed
       to about 70px, which for Japanese means one character per line: 「路地」
       and a whole paragraph ran down the left edge as a vertical column.
       Wrapping gives the title the full width and puts the stats under it. */
    .map-top{min-height:48px;padding:8px 12px;flex-wrap:wrap;align-items:flex-start}
    .map-heading{flex:1 1 100%;min-width:0}
    /* And the counters wrap too. Two of them fit; the third only appears once
       a review is due, which is why the row read fine until it did not - the
       screenshot that reported this had 「今日の復習」 cut off at the edge. */
    .map-progress{flex:1 1 100%;flex-wrap:wrap;row-gap:6px}
    .map-heading h2{font-size:1rem}
    .map-heading span{font-size:.64rem}
    .map-destination-label{margin-top:4px;padding:3px 5px;font-size:.62rem}
    .map-destination.is-stage .map-destination-label{margin-top:0}
    .map-home-icon{width:42px;height:42px}
    .map-detail{grid-template-columns:58px minmax(0,1fr);gap:9px;min-height:0;padding:11px 12px}
    .map-kon{width:56px;height:56px}
    .map-detail-name{font-size:1.05rem}
    .map-detail-story{font-size:.78rem}
    .map-detail-focus{font-size:.66rem}
    .map-detail-action{grid-column:1/-1;width:100%;min-width:0}
    .map-detail-check{grid-column:1/-1;width:100%;min-width:0}
  }

  @media(max-width:390px){
    .map-progress-lantern{display:none}
    .map-progress{font-size:.68rem}
    .map-destination-label{font-size:.58rem}
  }

  /* ---------- location screen ---------- */
  #screen-game{display:none;}

  .game-layout{
    display:grid;
    grid-template-columns:minmax(300px,38fr) minmax(0,62fr);
    grid-template-areas:"bar bar" "context answer";
    gap:14px 18px;
    align-items:start;
  }
  .stage-bar{grid-area:bar;min-width:0}
  .learning-context{grid-area:context;min-width:0}
  .answer-workspace{grid-area:answer;min-width:0}
  .stage-bar .hud{padding-bottom:8px;margin-bottom:8px}
  .stage-meta{display:flex;align-items:center;gap:8px 12px;flex-wrap:wrap}
  .stage-meta .scene-label,.stage-meta .stage-phase-row,.stage-meta .encounter-status{margin:0}
  .learning-context .narration{margin:0 0 10px}
  .learning-context .romaji-toggle{margin-bottom:8px}
  .learning-context .dialogue{margin-bottom:0}

  .hud{
    display:flex; align-items:center; justify-content:space-between;
    padding-bottom:14px; margin-bottom:16px;
    border-bottom:1px dashed rgba(27,42,74,0.22);
    gap:10px; flex-wrap:wrap;
  }
  .breadcrumb{
    background:none; border:none; cursor:pointer; font-family:inherit;
    font-size:0.82rem; font-weight:700; color:var(--ai-indigo);
    display:flex; align-items:center; gap:5px;
    /* 21px tall is a miss on a phone. The text stays the same size; the
       button grows to something a thumb can land on. */
    min-height:32px; padding:4px 2px;
  }
  .breadcrumb:hover{text-decoration:underline;}
  .hud-stars{
    font-family:'Zen Maru Gothic', sans-serif;
    font-weight:700; color:var(--momiji); font-size:0.92rem;
    display:flex; align-items:center; gap:4px;
  }
  .learning-hud{display:flex;align-items:center;gap:12px;margin-left:auto}
  .mastery-hud{display:grid;grid-template-columns:auto minmax(84px,150px) auto;align-items:center;gap:7px;font-size:.78rem;font-weight:700;color:#f7c877}
  /* The market and practice keep the light washi header (rgb 241,233,219),
     where the lantern yellow above measured about 1.3:1 and "known" all but
     vanished. The Inn and Entrance headers are dark and keep the yellow. */
  #screen-game:not(.inn-stage):not(.entrance-stage) .mastery-hud{color:#8a5a1f}
  #screen-game:not(.inn-stage):not(.entrance-stage) .mastery-hud .metric-gloss{color:rgba(74,52,35,.8)}
  .mastery-track{height:10px;border:1px solid rgba(247,200,119,.55);border-radius:99px;background:rgba(20,12,9,.55);overflow:hidden;box-shadow:inset 0 1px 3px rgba(0,0,0,.45)}
  .mastery-track span{display:block;width:0;height:100%;border-radius:inherit;background:linear-gradient(90deg,#d97835,#ffd36b);transition:width .35s ease}
  .money-hud{min-width:58px;padding:5px 9px;border:1px solid rgba(247,200,119,.5);border-radius:99px;background:rgba(28,16,10,.55);color:#ffe4a0;font-weight:800;text-align:center}
  .map-destination.state-locked{filter:grayscale(.8);opacity:.58}
  /* The row carries three things on a phone now, and on a 320px screen the
     third was pushed past the right edge rather than wrapping under. */
  @media(max-width:560px){.learning-hud{width:100%;justify-content:space-between;flex-wrap:wrap;row-gap:6px}.mastery-hud{flex:1;grid-template-columns:auto minmax(60px,1fr) auto}}

  .narration{
    font-size:0.9rem; color:#5a4d3f; font-style:italic;
    margin-bottom:14px; line-height:1.5;
  }

  .dialogue{
    display:flex; gap:12px; align-items:flex-start;
    background:rgba(27,42,74,0.05);
    border:1px solid rgba(27,42,74,0.12);
    border-radius:12px;
    padding:14px;
    margin-bottom:18px;
  }
  .dialogue.entrance-dialogue{
    background:transparent;
    border:none;
    padding:0;
    isolation:isolate;
  }
  .dialogue.entrance-dialogue .speech{
    background:#faf5f2;
    /* Painted light here, so it says what colour to read against it here.
       It did not, and the only rule that set the text dark was scoped to
       @media(min-width:761px) - so on a phone the card came out cream and the
       text kept the colour meant for reading against a dark scene. Pale on
       pale, and it was the question itself. Whichever rule paints a card owns
       the colour of the text on it. */
    color:#2d2926;
    border:1px solid rgba(27,42,74,0.12);
    border-radius:12px;
    padding:14px;
  }
  .avatar{
    flex:0 0 auto;
    width:52px; height:52px; border-radius:50%;
    background:radial-gradient(circle at 35% 30%, var(--lantern-bright), var(--lantern) 65%, #c97a28 100%);
    display:flex; align-items:center; justify-content:center;
    font-size:1.6rem;
    box-shadow:0 0 0 3px rgba(232,150,60,0.18), 0 4px 10px rgba(0,0,0,0.15);
    transition:width 0.15s ease, height 0.15s ease;
  }
  .avatar.avatar-animated{
    width:92px; height:92px;
    background:radial-gradient(circle at 35% 28%, rgba(247,200,119,0.35), rgba(232,150,60,0.12) 70%, transparent 100%);
    box-shadow:none;
  }
  .avatar.avatar-animated.entrance-fox{
    background:transparent;
    border-radius:0;
  }
  .avatar.avatar-animated .kon-photo-wrap{width:100%; height:100%;}

  .kon-photo-wrap{
    position:relative;
    transform-origin:50% 90%;
    animation:none;
  }
  .confused .kon-photo-wrap{
    animation:head-tilt-confused 0.7s ease-in-out 1;
  }
  .kon-photo{
    width:100%; height:100%;
    object-fit:contain;
    border-radius:50%;
    box-shadow:0 4px 12px rgba(36,31,28,0.28), 0 0 0 3px rgba(255,255,255,0.5);
    display:block;
    pointer-events:none;
    -webkit-user-drag:none;
    -webkit-touch-callout:none;
    user-select:none;
  }
  .entrance-fox .kon-photo{
    border-radius:0;
    background:transparent;
    box-shadow:none;
    filter:drop-shadow(0 6px 5px rgba(36,31,28,0.16));
    mix-blend-mode:normal;
  }
  .live-mouth{
    display:none;
    position:absolute;
    left:58%; top:47%;
    width:13%; height:auto;
    transform:translate(-50%, -50%) scale(0.9, 0.72);
    object-fit:contain;
    vertical-align:top;
    pointer-events:none;
    -webkit-user-drag:none;
    user-select:none;
  }
  .entrance-fox.talking .live-mouth{
    display:block;
    animation:live-mouth-talk 0.22s ease-in-out infinite alternate;
  }
  @keyframes live-mouth-talk{
    0%{transform:translate(-50%, -50%) scale(0.82, 0.55);}
    45%{transform:translate(-50%, -50%) scale(1.04, 1.12);}
    100%{transform:translate(-50%, -50%) scale(0.92, 0.78);}
  }

  @keyframes idle-bob{
    0%,100%{transform:translateY(0) rotate(0deg);}
    50%{transform:translateY(-2px) rotate(-1deg);}
  }
  @keyframes head-tilt-confused{
    0%,100%{transform:rotate(0deg);}
    30%{transform:rotate(-11deg);}
    60%{transform:rotate(7deg);}
  }

  .duo-stage{
    display:flex; flex-direction:column; align-items:center;
    margin-bottom:16px;
  }
  .player-figure{position:relative;width:84px;height:168px;}
  .entrance-player-art,.entrance-action-art{
    display:block;background-image:var(--player-action-sprite);background-repeat:no-repeat;
    background-size:400% 100%;background-position:0 center;
  }
  .entrance-player-art{position:absolute;inset:0;filter:drop-shadow(0 9px 7px rgba(0,0,0,.38));transform-origin:50% 92%;}
  .player-caption{
    font-size:0.68rem; font-weight:700; color:#8a7a5f;
    text-transform:uppercase; letter-spacing:0.08em; margin-top:2px;
  }
  .action-bow .entrance-player-art{background-position:33.333% center;animation:player-pose-pop 1.2s cubic-bezier(.25,1,.5,1) 1;}
  .action-wave .entrance-player-art{background-position:66.667% center;animation:player-pose-pop .9s cubic-bezier(.25,1,.5,1) 1;}
  .action-clap .entrance-player-art{background-position:100% center;animation:player-pose-pop .9s cubic-bezier(.25,1,.5,1) 1;}
  .action-try-again .entrance-player-art{background-position:0 center;animation:player-try-again .8s ease-in-out 1;}
  /* The success flourish must never pick its own sprite frame - it used to
     share the wave frame ("action-celebrate"), so a correct Bow flashed a
     wave. It now only glows/bounces over whatever pose is already showing. */
  .pose-correct .entrance-player-art{animation:player-pose-correct .8s ease-in-out 1;filter:drop-shadow(0 9px 7px rgba(0,0,0,.38)) drop-shadow(0 0 14px rgba(255,214,120,.85));}
  @keyframes player-pose-pop{0%{transform:translateY(3px) scale(.96)}18%,82%{transform:translateY(0) scale(1.02)}100%{transform:translateY(0) scale(1)}}
  @keyframes player-pose-correct{0%,100%{transform:translateY(0) scale(1)}40%{transform:translateY(-4px) scale(1.08)}}
  @keyframes player-try-again{0%,100%{transform:translateX(0)}30%{transform:translateX(-5px)}60%{transform:translateX(5px)}}

  /* Entrance tutorial: Kon, learner, dialogue and choices share one alley scene. */
  #screen-game.entrance-stage{
    max-width:1000px;
    min-height:min(690px,calc(100svh - 36px));
    overflow:hidden;
    color:#fff5df;
    background:
      linear-gradient(180deg,rgba(5,11,24,.08) 25%,rgba(5,11,24,.7) 100%),
      url("assets/entrance/wooden-gate-v1.webp") center/cover no-repeat;
    box-shadow:0 28px 70px rgba(3,7,20,.62),0 0 0 1px rgba(247,200,119,.18);
  }
  #screen-game.entrance-stage::before{border-color:rgba(247,207,137,.34);z-index:7}
  .entrance-stage .game-layout{position:relative;min-height:min(630px,calc(100svh - 92px));grid-template-columns:repeat(12,minmax(0,1fr));grid-template-rows:auto minmax(0,1fr);gap:0;align-items:stretch}
  .entrance-stage .stage-bar{grid-column:1/-1;grid-row:1;position:relative;z-index:4;padding:10px 14px;border:2px solid #8c562d;border-radius:12px;background:linear-gradient(180deg,rgba(92,49,25,.95),rgba(51,27,17,.96));box-shadow:inset 0 0 0 2px rgba(244,202,128,.2),0 6px 18px rgba(0,0,0,.32);backdrop-filter:blur(4px)}
  .entrance-stage .hud{margin-bottom:6px;padding-bottom:6px;border-color:rgba(247,215,159,.28)}
  .entrance-stage .breadcrumb,.entrance-stage .scene-label{color:#fff0cf}
  .entrance-stage .hud-stars{color:#f3be6d}
  .entrance-progress{margin-left:auto;padding:4px 10px;border:1px solid rgba(247,211,147,.42);border-radius:999px;background:rgba(167,75,47,.68);color:#fff5df;font-family:'Shippori Mincho',serif;font-size:.78rem;font-weight:800;letter-spacing:.05em}
  .entrance-stage .learning-context,.entrance-stage .answer-workspace{position:relative;min-height:0}
  .entrance-stage .answer-workspace{grid-column:1/-1;grid-row:2;z-index:2;display:block;padding:0}
  .entrance-stage .learning-context{grid-column:1/7;grid-row:2;z-index:5;align-self:end;display:block;margin:0 0 12px 12px;padding:22px 10px 10px;border:2px solid #8c562d;border-radius:12px;background:linear-gradient(180deg,rgba(92,49,25,.96),rgba(48,25,16,.97));box-shadow:inset 0 0 0 2px rgba(244,202,128,.18),0 8px 22px rgba(0,0,0,.42)}
  .entrance-stage .narration{position:absolute;left:0;bottom:calc(100% + 10px);max-width:390px;margin:0;padding:7px 10px;border-radius:8px;background:rgba(10,20,38,.78);color:#f1dfbd;font-style:normal;font-size:.75rem}
  .entrance-stage .romaji-toggle{position:absolute;right:10px;top:3px;margin:0;padding:3px 6px;border-radius:7px;color:#f1dfbd;font-size:.63rem}
  .entrance-stage .dialogue.entrance-dialogue{position:relative;display:block;margin:0;padding:0;background:transparent;box-shadow:none}
  .entrance-stage .dialogue.entrance-dialogue::before{content:"コン (Kon)";position:absolute;left:8px;top:-38px;padding:5px 12px;border:2px solid #8c562d;border-radius:9px 9px 0 0;background:#5a321d;color:#ffe8b8;font-family:'Shippori Mincho',serif;font-size:.72rem;font-weight:800;letter-spacing:.04em}
  .entrance-stage .dialogue.entrance-dialogue .speech{min-height:104px;padding:15px 42px 12px 14px;border:2px solid rgba(156,95,48,.8);background:linear-gradient(180deg,#fffaf0,#efe0be);color:#2d2926;box-shadow:0 5px 0 rgba(55,30,18,.76)}
  .entrance-stage .speak-btn{position:absolute;right:10px;bottom:12px;margin:0}
  .entrance-stage #scene{position:relative;display:block;min-height:100%;height:100%;padding:0;background:transparent}
  .entrance-stage .duo-stage{position:absolute;left:39%;bottom:142px;z-index:3;margin:0;transform:translateX(-50%)}
  .entrance-stage .player-figure{width:170px;height:340px}
  /* The learner's own label, given the ground the speech tag beside it has.
     It sat directly under the narration bar - bottom edge and caption top at
     the same pixel - so the bar's shadow cut the tops off あなた and it read
     as ちなた. A label that names who is on screen cannot be the one thing on
     the screen that is hard to read. */
  .entrance-stage .player-caption{
    position:relative; z-index:5;
    margin-top:8px; padding:3px 9px;
    border:1px solid rgba(247,200,119,.45); border-radius:7px;
    background:rgba(28,16,10,.78);
    color:#ffe8b8; letter-spacing:.1em;
  }
  .entrance-stage #scene > .avatar.avatar-animated{position:absolute;width:170px;height:220px;left:61%;bottom:150px;z-index:3;filter:drop-shadow(0 10px 8px rgba(0,0,0,.42))}
  .entrance-control-help{grid-column:1/-1;position:static;z-index:auto;width:auto;padding:0 4px 1px;text-align:center;background:transparent;color:#fff0cf}
  .entrance-control-help strong{display:block;color:#f2c87d;font-size:.61rem;letter-spacing:.12em;text-transform:uppercase}
  .entrance-control-help span{display:block;margin-top:2px;font-size:.67rem;line-height:1.3}
  .entrance-stage .entrance-action-grid{position:absolute;right:12px;bottom:12px;z-index:5;display:grid;width:45%;min-height:158px;grid-template-columns:repeat(3,minmax(0,1fr));grid-template-rows:auto minmax(0,1fr);gap:7px;padding:8px;border:2px solid #8c562d;border-radius:12px;background:linear-gradient(180deg,rgba(92,49,25,.96),rgba(48,25,16,.97));box-shadow:inset 0 0 0 2px rgba(244,202,128,.18),0 8px 22px rgba(0,0,0,.42);opacity:0;visibility:hidden;transform:translateY(7px);transition:opacity .18s ease,transform .18s cubic-bezier(.22,1,.36,1),visibility 0s linear .18s}
  .entrance-stage #scene.entrance-actions-visible .entrance-action-grid{opacity:1;visibility:visible;transform:translateY(0);transition-delay:0s}
  /* #scene fills the whole grid row, so .next-row lands below the stage and
     out of the viewport. Once the tutorial is answered the action dock has
     done its job, so the continue button takes that slot. */
  .entrance-stage.entrance-complete .entrance-action-grid,
  .entrance-stage.entrance-complete .entrance-control-help{display:none}
  /* Only take the dock slot where the stage fits the viewport. On a phone the
     Entrance is taller than the screen, so absolute positioning would put the
     button below the fold - there the shared sticky rule must win instead. */
  @media(min-width:761px){
    .entrance-stage .next-row{position:absolute;right:12px;bottom:12px;z-index:7;width:43%;margin:0}
    .entrance-stage .next-row .btn{width:100%}
    .entrance-stage.entrance-complete .feedback-row{position:absolute;right:12px;bottom:70px;z-index:7;width:43%;margin:0;justify-content:center}
  }
  /* #screen-game.entrance-stage is overflow:hidden so the alley cannot spill.
     That also clips anything after #scene, and stops position:sticky pinning
     (sticky needs a scrolling ancestor). On a phone the stage is taller than
     the screen, so the result and the continue button were clipped away
     entirely - not merely below the fold. Fixed positioning escapes the clip. */
  @media(max-width:760px){
    /* .answer-workspace is z-index:2, so a z-index on the rows inside it cannot
       beat .learning-context at z-index:5. Lift the workspace - but only here,
       because on desktop it would also lift #scene over the dialogue. */
    .entrance-stage.entrance-complete .answer-workspace{z-index:21}
    .entrance-stage.entrance-complete .feedback-row,
    .entrance-stage.entrance-complete .next-row{position:fixed;left:0;right:0;z-index:20;margin:0;padding-left:14px;padding-right:14px}
    .entrance-stage.entrance-complete .next-row{bottom:0;padding-top:10px;padding-bottom:calc(10px + env(safe-area-inset-bottom,0px));background:linear-gradient(180deg,rgba(228,217,194,0),var(--washi-dim) 38%)}
    .entrance-stage.entrance-complete .feedback-row{bottom:calc(62px + env(safe-area-inset-bottom,0px));justify-content:center;padding-top:6px;padding-bottom:6px;background:var(--washi-dim)}
    /* The stage is taller than a short phone, so the dialogue is anchored to a
       stage bottom that sits below the viewport while the dock is anchored to
       the viewport - they collided over Kon's line. Pin the dialogue too. */
    .entrance-stage.entrance-complete .learning-context{position:fixed;left:8px;right:8px;bottom:calc(124px + env(safe-area-inset-bottom,0px));z-index:22;margin:0;max-height:42svh;overflow-y:auto}
    .entrance-stage.entrance-complete .narration{display:none}
  }
  .entrance-stage .hotspot{min-width:0;min-height:112px;padding:5px 4px;border:2px solid rgba(156,95,48,.82);background:linear-gradient(180deg,rgba(255,250,236,.98),rgba(236,216,177,.97));box-shadow:0 4px 0 rgba(31,17,11,.82)}
  .entrance-action-art{width:50px;height:90px;flex:0 0 auto;filter:drop-shadow(0 4px 3px rgba(62,37,23,.22))}
  .entrance-action-art-bow{background-position:33.333% center}
  .entrance-action-art-wave{background-position:66.667% center}
  .entrance-action-art-clap{background-position:100% center}

  @media(max-width:760px){
    #screen-game.entrance-stage{min-height:0;padding:12px;background-position:54% top}
    .entrance-stage .game-layout{display:grid;grid-template-columns:1fr;grid-template-rows:auto minmax(616px,1fr);min-height:0;gap:0}
    .entrance-stage .stage-bar{grid-column:1;grid-row:1}
    .entrance-stage .answer-workspace{grid-column:1;grid-row:2;padding:0}
    .entrance-stage .learning-context{grid-column:1;grid-row:2;align-self:end;margin:0 9px 10px;padding:20px 8px 8px}
    .entrance-stage .game-layout:has(#scene.entrance-actions-visible) .learning-context{margin-bottom:162px}
    /* With Wave, Bow and Clap on screen the panel is lifted 162px, and since
       the romaji row moved beside Kon's tab (v480) the narration above it
       covered the あなた label. The scene is set by then; the strip goes. */
    .entrance-stage .game-layout:has(#scene.entrance-actions-visible) .narration{display:none}
    .entrance-stage .narration{left:0;bottom:calc(100% + 8px);max-width:100%;font-size:.68rem}
    /* The romaji switch (44px tall) shares the row with Kon's name tab, fully
       above the bubble. With 20px of top padding it reached 24px into the
       bubble at 390px and was half hidden behind it; at 360px it took a row
       of its own, which grew the panel until the narration above it covered
       the characters. */
    .entrance-stage .learning-context{padding-top:48px}
    .entrance-stage .romaji-toggle{right:7px;top:2px}
    .entrance-stage .dialogue.entrance-dialogue .speech{min-height:96px;padding:12px 38px 10px 12px}
    /* 56px taller than the figures need, so the narration strip above Kon's
       dialogue has its own band: at 560px it sat over Kon's legs and cut the
       あなた label in half. */
    .entrance-stage #scene{min-height:616px}
    .entrance-stage .duo-stage{left:35%;bottom:358px}
    .entrance-stage .player-figure{width:112px;height:224px}
    .entrance-stage #scene > .avatar.avatar-animated{width:112px;height:145px;left:65%;bottom:358px}
    /* A wrong action is answered by Kon's own line - 「ちがいますね。もう一度
       どうぞ。」 - and by the player's try-again pose. The generic correction
       under it was pinned to the bottom of the screen, which is exactly where
       Wave, Bow and Clap sit, so it hid the buttons the learner needed next. */
    .entrance-stage:not(.entrance-complete) .answer-workspace #feedback-row.show{display:none}
    .entrance-stage .entrance-action-grid{grid-template-columns:repeat(3,minmax(0,1fr))}
    .entrance-stage .entrance-action-grid{right:8px;bottom:8px;width:calc(100% - 16px);min-height:145px;padding:7px 6px 6px}
    .entrance-stage .hotspot{min-height:76px;font-size:.7rem}
    .entrance-action-art{width:35px;height:64px}
  }

  @media(prefers-reduced-motion:reduce){
    .entrance-player-art{animation:none!important;transition:none!important}
    .entrance-control-help,.entrance-stage .entrance-action-grid{transition:none}
  }
  .speech{flex:1; min-width:0; position:relative; padding:4px 36px 4px 4px; border-radius:10px;}
  .speech.dialogue-speaking,.speech.dialogue-ready{cursor:pointer;}
  .speech.dialogue-speaking:hover,.speech.dialogue-ready:hover{background:rgba(255,255,255,.48);}
  .speech.dialogue-speaking:focus-visible,.speech.dialogue-ready:focus-visible{outline:3px solid var(--lantern-bright);outline-offset:3px;}
  .speech-top{display:flex; align-items:center; justify-content:space-between; gap:8px;}
  .jp-line{
    font-family:'Shippori Mincho', serif;
    font-size:1.35rem;
    font-weight:600;
    line-height:1.4;
  }
  .speak-btn{
    background:none; border:none; cursor:pointer; font-size:1.15rem;
    color:var(--ai-indigo); flex:0 0 auto; padding:2px 4px; border-radius:6px;
  }
  .speak-btn:hover{background:rgba(27,42,74,0.08);}
  .speak-btn:focus-visible{outline:2px solid var(--lantern-bright);}
  .listen-again{display:inline-flex;align-items:center;justify-content:center;gap:5px;min-height:32px;padding:5px 9px;border:1px solid rgba(140,86,45,.72);border-radius:999px;background:#fff7e5;color:#5c3824;font:inherit;font-size:.68rem;font-weight:800;line-height:1;cursor:pointer;box-shadow:0 2px 0 rgba(73,43,24,.45)}
  .listen-again:hover{background:#fffdf6;transform:translateY(-1px)}
  .listen-again:focus-visible{outline:3px solid var(--lantern-bright);outline-offset:2px}
  .dialogue-continue{
    position:absolute;right:8px;bottom:7px;display:grid;place-items:center;
    min-width:24px;height:24px;padding:0 5px;border-radius:999px;
    color:#fff;background:var(--ai-indigo);font-size:1rem;font-weight:800;
    line-height:1;opacity:0;transform:translateY(3px);transition:opacity .16s ease,transform .16s ease;
  }
  .speech.dialogue-speaking .dialogue-continue,.speech.dialogue-ready .dialogue-continue{opacity:1;transform:none;}
  .speech.dialogue-ready .dialogue-continue{background:var(--moss);animation:dialogue-nudge 1.15s ease-in-out infinite;}
  @keyframes dialogue-nudge{0%,100%{transform:translateY(0)}50%{transform:translateY(3px)}}
  .romaji-line{
    font-size:0.86rem; color:#6b5f4f; margin-top:3px;
  }
  .meaning-line{
    font-size:0.84rem; color:var(--moss); margin-top:6px; font-weight:700;
    display:none;
  }
  .meaning-line.show{display:block;}

  .romaji-toggle{
    display:flex; align-items:center; gap:6px;
    font-size:0.72rem; color:#6b5f4f; letter-spacing:0.03em;
    margin-bottom:14px; justify-content:flex-end;
  }
  .switch{
    width:34px; height:19px; border-radius:999px;
    background:rgba(27,42,74,0.22);
    position:relative; cursor:pointer; border:none; flex:0 0 auto;
  }
  /* The pill is meant to look small. The area you can hit should not be: this
     extends the target to 34x34 without changing the layout or the drawing. */
  .switch::before{
    content:""; position:absolute; left:50%; top:50%;
    width:100%; height:34px; transform:translate(-50%,-50%);
  }
  .switch::after{
    content:""; position:absolute; top:2px; left:2px;
    width:15px; height:15px; border-radius:50%;
    background:var(--washi);
    transition:transform 0.15s ease;
  }
  .switch.on{background:var(--moss);}
  .switch.on::after{transform:translateX(15px);}

  .scene-label{
    font-size:0.72rem; text-transform:uppercase; letter-spacing:0.09em;
    color:#8a7a5f; font-weight:700; margin-bottom:8px;
  }
  .stage-phase-row{display:none;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px}
  .stage-intro-action{display:flex;justify-content:center;padding:24px 12px}
  .stage-phase-badge{display:inline-flex;align-items:center;border-radius:999px;padding:5px 10px;background:var(--ai-indigo);color:var(--washi);font-size:.72rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase}
  /* A coarse pointer needs something to land on: at 5px of padding this chip
     came out 28px tall, well under the 44px touch minimum the rest of the
     game's controls keep. Height only - the label stays the same size. */
  .stage-restart{padding:5px 10px;font-size:.72rem}
  @media(pointer:coarse){.stage-restart{min-height:44px;padding-inline:12px}}
  .encounter-status{
    display:none; margin:-3px 0 10px; color:var(--momiji);
    font-size:0.72rem; font-weight:700; letter-spacing:0.08em;
    text-transform:uppercase;
  }

  .scene{
    background:rgba(27,42,74,0.04);
    border:1px dashed rgba(27,42,74,0.2);
    border-radius:12px;
    padding:18px;
    min-height:120px;
  }

  .hotspots{
    display:flex; flex-wrap:wrap; gap:12px; justify-content:center;
  }
  .hotspot{
    background:var(--washi);
    border:1.5px solid rgba(27,42,74,0.16);
    border-radius:12px;
    padding:14px 16px;
    display:flex; flex-direction:column; align-items:center; gap:6px;
    cursor:pointer; min-width:84px;
    font-family:'Zen Maru Gothic', sans-serif; font-weight:600; font-size:0.8rem;
    color:var(--sumi);
    transition:transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
  }
  .hotspot:hover{transform:translateY(-2px); box-shadow:0 8px 16px rgba(27,42,74,0.14); border-color:var(--lantern);}
  .hotspot:focus-visible{outline:3px solid var(--lantern-bright); outline-offset:1px;}
  .hotspot .emoji{font-size:1.9rem;}
  .hotspot.selected{border-color:var(--lantern); background:#fdf3e2; box-shadow:0 0 0 3px rgba(232,150,60,0.22);}

  .path-row{display:flex; gap:16px; justify-content:center;}
  .path-card{
    flex:1; max-width:220px;
    background:var(--washi); border:1.5px solid rgba(27,42,74,0.16); border-radius:12px;
    padding:20px 12px; text-align:center; cursor:pointer;
    transition:transform 0.12s ease, box-shadow 0.12s ease;
  }
  .path-card:hover{transform:translateY(-2px); box-shadow:0 8px 16px rgba(27,42,74,0.14); border-color:var(--lantern);}
  .path-card .emoji{font-size:2.1rem; display:block; margin-bottom:6px;}
  .path-card span{font-weight:700; font-size:0.85rem;}

  .count-wrap{text-align:center;}
  .count-grid{
    display:flex; flex-wrap:wrap; gap:10px; justify-content:center; margin-bottom:14px;
  }
  .count-item{
    width:56px; height:56px; border-radius:10px;
    background:var(--washi); border:1.5px solid rgba(27,42,74,0.16);
    font-size:1.7rem; cursor:pointer;
    display:flex; align-items:center; justify-content:center;
    transition:transform 0.12s ease, box-shadow 0.12s ease;
  }
  .count-item:hover{transform:translateY(-2px);}
  .count-item.picked{border-color:var(--lantern); background:#fdf3e2; box-shadow:0 0 0 3px rgba(232,150,60,0.22);}
  .count-status{font-size:0.85rem; color:#5a4d3f; margin-bottom:12px; font-weight:700;}

  .yesno-row{display:flex; gap:18px; justify-content:center;}
  .yesno-card{
    background:var(--washi); border:1.5px solid rgba(27,42,74,0.16); border-radius:14px;
    padding:16px 22px; text-align:center; cursor:pointer; min-width:110px;
    transition:transform 0.12s ease, box-shadow 0.12s ease;
  }
  .yesno-card:hover{transform:translateY(-2px); box-shadow:0 8px 16px rgba(27,42,74,0.14); border-color:var(--lantern);}
  .yesno-card .emoji{font-size:2.4rem; display:block; margin-bottom:4px;}
  .yesno-card .jp{font-weight:700; font-size:1.05rem;}
  .sky-strip{
    text-align:center; font-size:1.8rem; letter-spacing:6px; margin-bottom:16px; opacity:0.9;
  }

  .finale-wrap{text-align:center;}
  .finale-wrap p{font-size:0.85rem; color:#5a4d3f; margin:0 0 14px;}

  .hint-btn{
    display:block; margin:14px auto 0; background:none; border:none; cursor:pointer;
    color:#8a7a5f; font-size:0.78rem; text-decoration:underline; font-family:inherit;
    min-height:32px; padding:6px 10px;   /* was 20px tall: too small to hit */
  }
  .hint-box{
    display:none; margin-top:10px; background:rgba(126,161,132,0.14);
    border:1px solid rgba(126,161,132,0.35); border-radius:8px;
    padding:10px 12px; font-size:0.82rem; color:#3d5a43;
  }
  .hint-box.show{display:block;}

  .feedback-row{
    margin-top:18px; display:none; align-items:center; gap:14px; justify-content:center;
    flex-wrap:wrap; text-align:center;
  }
  .feedback-row.show{display:flex;}
  .stamp{
    font-family:'Shippori Mincho', serif;
    font-weight:800; font-size:1.05rem;
    border:3px solid var(--momiji); color:var(--momiji);
    border-radius:10px; padding:6px 14px;
    transform:rotate(-7deg) scale(0.6);
    opacity:0;
    animation:stamp-in 0.35s ease forwards;
  }
  .stamp.good{border-color:var(--moss); color:var(--moss);}
  @keyframes stamp-in{
    to{transform:rotate(-7deg) scale(1); opacity:1;}
  }
  .feedback-text{font-size:0.86rem; color:#4a4038; max-width:32ch; text-align:left;}
  .feedback-text b{color:var(--ai-indigo);}
  .episode-target-reveal{display:block;margin-top:7px;padding-top:7px;border-top:1px solid rgba(108,77,47,.24);font-family:'Shippori Mincho',serif;font-weight:700;color:#513519;line-height:1.45}

  .next-row{margin-top:18px; text-align:center;}
  /* On a phone the answer room is taller than the screen, so a continue button
     sitting after it is below the fold and easy to miss. Pin it instead. */
  @media(max-width:760px){
    .next-row{
      position:sticky;
      bottom:0;
      z-index:12;
      margin:12px -22px 0;
      padding:10px 22px calc(10px + env(safe-area-inset-bottom, 0px));
      background:linear-gradient(180deg, rgba(228,217,194,0) 0%, var(--washi-dim) 38%);
    }
    .next-row .btn{width:100%; max-width:340px;}

    /* The correction is pinned with it, and for the same reason.
       The button was pinned and the explanation was not, so on an 800px phone
       a wrong answer put its continue button on screen and its explanation
       five hundred pixels below the fold - the game looked like it had simply
       accepted the answer and moved on. That explanation names the word the
       learner reached for instead of the one they wanted, which is the most
       useful thing the stage says, and on a phone nobody had ever seen it.
       Pinned rather than scrolled to: the retry re-renders the room a moment
       later, which undid any scrolling. */
    .answer-workspace #feedback-row.show{
      position:sticky;
      /* Clear of the pinned button rather than on top of it: both were stuck
         to bottom:0 and landed in the same place. 72px is that button's own
         height, measured: a 50px button inside 10px of padding either side, and the
         safe-area inset is added because the button's padding carries it too,
         so on a phone with a home indicator it grows and this must grow with
         it. */
      bottom:calc(72px + env(safe-area-inset-bottom, 0px));
      z-index:11;
      margin:10px -22px 0;
      padding:10px 22px;
      border-radius:0;
      background:var(--washi-dim);
      box-shadow:0 -6px 14px rgba(0,0,0,.22);
    }
    /* Stacked, the continue button sits under the correction rather than
       overlapping it. */
    .answer-workspace:has(#feedback-row.show) .next-row{margin-top:0}
  }

  /* On a phone the feedback button now sits in the flow just above this line
     rather than floating over it, so the credit needs no room kept for it. */
  footer.credits{
    text-align:center; color:rgba(242,235,221,0.35); font-size:0.72rem; margin-top:18px;
  }
  .stage:has(#screen-game:not(.hidden)) footer.credits{margin-top:8px}

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

  .answer-workspace .scene{background:transparent;border:0;border-radius:0;padding:0;min-height:0}
  .answer-workspace .duo-stage{width:100%;min-height:0;margin:0;justify-content:center}

  @media(max-width:760px){
    body{padding:8px 8px 18px}
    .stage{max-width:680px}
    .frame{padding:14px 14px 18px}
    /* Neither screen has anything worth reaching near its own bottom edge -
       the map's pins sit in its fixed-ratio picture and the home menu sits
       right under the scene - so unlike the entrance and the Inn's room,
       filling the card here cannot push a target further from the thumb.
       Without this, a portrait phone showed the map or the house as a short
       card with a third of the screen left as bare background beneath it. */
    /* dvh, not svh. svh is the viewport at its SMALLEST - measured with the
       phone browser's toolbar showing - so once that toolbar slid away on
       scroll the visible area grew past the card and left the same gap this
       rule exists to close. dvh tracks the real visible height as the
       toolbar moves. A desktop browser has no toolbar that collapses, so
       there svh and dvh are identical and only a real phone shows the
       difference. The plain vh line is the fallback for engines with
       neither; overshooting by a toolbar's height there costs a little
       scroll, which is the better way to be wrong. */
    #screen-map,#screen-game.home-stage{min-height:calc(100vh - 26px)}
    #screen-map,#screen-game.home-stage{min-height:calc(100dvh - 26px)}
    /* The leftover height goes to the map, not to the card under it.
       The frame is told to fill the phone, and the detail card was taking the
       slack: 194px of empty cream sat between 覚えた言葉 0 / 40 and the
       button that acts on it, a quarter of the screen saying nothing. The
       alley itself is worth looking at, so it grows instead and the card
       stays the height of what it holds. */
    #screen-map .map-scene{flex:1 1 auto;min-height:0}
    #screen-map .map-detail{flex:0 0 auto;align-content:start}
    /* Making the card tall only moved the empty space inside it. Something
       has to actually take the height.
       The map picture cannot: its pins are placed at percentages over a
       background sized `cover`, so a taller box crops the artwork sideways
       and every pin slides off the building it points at. The picture keeps
       its 3/2, and the sheet under it grows instead - which is the half
       worth growing anyway, since that is where the story text and the
       button that starts the place live. */
    .map-scene{flex:0 0 auto}
    /* space-between, not center: centring left the sheet's content floating
       in the middle of a cream void. Pushed apart, the place's name and story
       sit at the top where reading starts and the button that enters it sits
       at the bottom, which is both where the layout wants a base and where a
       thumb already is. */
    /* One gap, not two. The name, the story and the progress belong together
       as a single block at the top; only the button wants the bottom, so the
       last row takes the slack and the button sits at the end of it. */
    .map-detail{flex:1 1 auto;grid-template-rows:auto auto 1fr;row-gap:12px}
    .map-detail-action{align-self:end}
    .game-layout{display:block}
    .stage-bar{margin-bottom:10px}
    .stage-bar .hud{padding-bottom:7px;margin-bottom:7px}
    .stage-meta{gap:6px 8px}
    .stage-meta .scene-label{width:100%;margin-bottom:0}
    .learning-context{display:contents}
    .learning-context .narration{margin-bottom:8px}
    .learning-context .romaji-toggle{margin-bottom:7px}
    .learning-context .dialogue{position:sticky;top:8px;z-index:8;margin-bottom:12px;padding:10px;background:#f2eadb;box-shadow:0 8px 18px rgba(27,42,74,.16)}
    .learning-context .dialogue.entrance-dialogue{background:rgba(242,235,221,.96);padding:6px}
    /* The card is light here, and the text colour that goes with it was two
       hundred lines away inside @media(min-width:761px) - so on a phone the
       card turned cream and the text kept the colour meant for reading
       against a dark scene. Pale on pale, and it was the question itself:
       reported from an Episode 2 screen where the whole prompt was a ghost.
       Whichever rule paints the card has to set its text colour too. */
    .learning-context .dialogue,
    .learning-context .dialogue .speech,
    .learning-context .dialogue .jp-line{color:#2d2926}
    .learning-context .dialogue .romaji-line{color:#6b5f4f}
    .avatar.avatar-animated{width:68px;height:68px}
    .jp-line{font-size:1.1rem}
    .romaji-line{font-size:.8rem;line-height:1.35}
  }

  @media(min-width:761px) and (max-height:800px){
    body{padding:8px 12px 16px}
    #screen-game{padding:12px 14px 14px}
    .game-layout{gap:8px 14px}
    .stage-bar .hud{padding-bottom:5px;margin-bottom:5px}
    .learning-context .narration{font-size:.82rem;line-height:1.35;margin-bottom:6px}
    .learning-context .romaji-toggle{margin-bottom:5px}
    .learning-context .dialogue{padding:10px}
    .avatar.avatar-animated{width:72px;height:72px}
    .jp-line{font-size:1.1rem}
    .romaji-line{font-size:.78rem;line-height:1.3}
  }

  /* Moonview Inn uses the Entrance's cinematic wood-and-washi shell while
     leaving the illustrated room as the primary answer surface. */
  #screen-game.inn-stage{
    max-width:1100px;
    min-height:min(690px,calc(100svh - 36px));
    padding:14px;
    color:#fff4da;
    background-image:linear-gradient(rgba(6,12,24,.12),rgba(6,12,24,.42)),var(--inn-scene-image,linear-gradient(145deg,#081126,#101d36 58%,#080f20));
    background-size:cover;
    background-position:center;
    box-shadow:0 28px 70px rgba(3,7,20,.62),0 0 0 1px rgba(247,200,119,.18);
  }
  #screen-game.inn-stage::before{border-color:rgba(247,207,137,.34)}
  .inn-stage .game-layout{display:grid;min-height:calc(min(690px,100svh - 64px) - 28px);grid-template-columns:repeat(12,minmax(0,1fr));grid-template-rows:auto minmax(0,1fr);gap:12px;align-items:stretch}
  .inn-stage .stage-bar{grid-column:1/-1;grid-row:1;padding:9px 13px;border:2px solid #8c562d;border-radius:12px;background:rgba(62,32,19,.86);backdrop-filter:blur(10px) saturate(115%);box-shadow:inset 0 1px rgba(244,202,128,.2),0 7px 20px rgba(0,0,0,.32)}
  .inn-stage .hud{margin-bottom:5px;padding-bottom:5px;border-color:rgba(247,215,159,.28)}
  .inn-stage .breadcrumb,.inn-stage .scene-label{color:#fff0cf}
  .inn-stage .hud-stars{color:#f3be6d}
  .inn-stage .stage-phase-badge{background:#9b4e32;color:#fff3d7}
  .inn-stage .stage-restart{border-color:#c38a56;background:#f5e4bf;color:#4a2b1b}
  /* Five visible stops make the Inn read as a finite route, not one endless
     bank of questions. The lamp is the progress signal; text remains the
     fallback for zoom, contrast modes, and learners who do not read colour. */
  .inn-journey{flex-basis:100%;margin:-1px 0 0;padding:6px 0 0;border-top:1px solid rgba(247,215,159,.22)}
  .inn-journey-status{margin:0 0 4px;color:#f7dfab;font-size:.68rem;font-weight:800;line-height:1.2}
  .inn-journey-stops{display:grid;grid-template-columns:1.4fr repeat(4,minmax(0,1fr));gap:3px;margin:0;padding:0;list-style:none}
  .inn-journey-stop{position:relative;display:grid;grid-template-columns:12px minmax(0,1fr);grid-template-areas:"lamp label" "lamp reward";column-gap:4px;align-items:center;min-width:0;padding:4px 5px;border:1px solid rgba(224,164,79,.24);border-radius:7px;background:rgba(19,11,8,.26);color:#cbb495}
  .inn-journey-lamp{grid-area:lamp;display:block;width:9px;height:9px;border:1px solid #c7893d;border-radius:50%;background:rgba(255,232,181,.12);box-shadow:inset 0 0 3px rgba(0,0,0,.35)}
  .inn-journey-label{grid-area:label;overflow:hidden;font-size:.58rem;font-weight:900;line-height:1.1;text-overflow:ellipsis;white-space:nowrap}
  .inn-journey-reward{grid-area:reward;overflow:hidden;font-size:.5rem;line-height:1.1;opacity:.82;text-overflow:ellipsis;white-space:nowrap}
  .inn-journey-stop.is-complete{border-color:rgba(246,190,98,.58);color:#f7dfab;background:rgba(117,72,26,.32)}
  .inn-journey-stop.is-complete .inn-journey-lamp{background:#efb95d;box-shadow:0 0 7px rgba(246,190,98,.8),inset 0 0 2px rgba(255,255,255,.9)}
  .inn-journey-stop.is-current{border-color:#ffe1a0;color:#fff4d7;background:rgba(151,91,32,.52);box-shadow:0 0 0 1px rgba(255,213,135,.18)}
  .inn-journey-stop.is-current .inn-journey-lamp{background:#fff0b7;box-shadow:0 0 10px rgba(255,196,90,.95),inset 0 0 2px rgba(255,255,255,.9);animation:inn-lantern-light .42s ease-out both}
  .inn-journey-stop.is-locked{opacity:.68}
  @keyframes inn-lantern-light{0%{transform:scale(.55);opacity:.35}65%{transform:scale(1.25);opacity:1}100%{transform:scale(1);opacity:1}}

  .inn-stage .answer-workspace:has(.inn-reward){align-self:stretch;display:grid;place-items:center;min-height:0}
  .inn-stage .game-layout:has(.inn-reward){grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr);align-items:stretch}
  .inn-stage .game-layout:has(.inn-reward) .learning-context{display:none}
  .inn-stage .game-layout:has(.inn-reward) .answer-workspace{grid-column:1;grid-row:2;align-self:stretch;padding:0}
  .inn-stage .game-layout:has(.inn-reward) .answer-workspace .scene{height:100%;display:flex;align-items:center;justify-content:center;overflow:visible}
  .inn-reward{position:relative;isolation:isolate;display:grid;justify-items:center;gap:7px;width:min(520px,100%);margin:auto;padding:24px 22px 20px;overflow:hidden;border:2px solid rgba(236,177,83,.9);border-radius:16px;background:linear-gradient(150deg,rgba(255,250,237,.98),rgba(244,220,170,.96));box-shadow:0 12px 0 rgba(54,27,13,.68),0 18px 32px rgba(0,0,0,.32);color:#392515;text-align:center;animation:inn-reward-settle .65s cubic-bezier(.22,1,.36,1) both}
  .inn-reward::before{content:"";position:absolute;z-index:-1;inset:-40%;background:radial-gradient(circle,rgba(255,223,137,.78),transparent 48%);opacity:.7}
  .inn-reward-image{position:relative;z-index:1;width:min(150px,54%);max-height:128px;object-fit:contain;filter:drop-shadow(0 7px 5px rgba(50,28,12,.26));animation:inn-reward-settle .65s .05s cubic-bezier(.22,1,.36,1) both}
  .inn-reward-kicker{margin:0;color:#94582a;font-size:.68rem;font-weight:900;letter-spacing:.14em;text-transform:uppercase}
  .inn-reward h2{font-family:'Shippori Mincho',serif;font-size:1.55rem;color:#3d2717}
  .inn-reward p:not(.inn-reward-kicker):not(.inn-reward-coins){max-width:34ch;margin:0;color:#65462f;font-size:.84rem;line-height:1.45}
  .inn-reward-coins{margin:0;color:#8c4e1e;font-size:.83rem;font-weight:900}
  .inn-reward-actions{display:flex;justify-content:center;gap:8px;flex-wrap:wrap;margin-top:4px}
  .inn-reward-spark{position:absolute;z-index:0;width:8px;height:8px;border-radius:50%;background:#ffd66f;box-shadow:0 0 10px #f2a840;animation:inn-spark .9s ease-out both}
  .inn-reward-spark-one{left:14%;top:20%}.inn-reward-spark-two{right:15%;top:34%;animation-delay:.14s}
  @keyframes inn-reward-settle{0%{transform:translateY(22px) scale(.9);opacity:0}68%{transform:translateY(-3px) scale(1.025);opacity:1}100%{transform:translateY(0) scale(1);opacity:1}}
  @keyframes inn-spark{0%{transform:scale(.2);opacity:0}45%{transform:scale(1.3);opacity:1}100%{transform:translateY(-15px) scale(.4);opacity:0}}
  .inn-stage .learning-context{grid-column:1/5;grid-row:2;position:relative;align-self:stretch;display:flex;flex-direction:column;justify-content:flex-end;min-width:0;min-height:0;padding:22px 10px 10px;border:0;border-radius:13px;background:transparent;box-shadow:none}
  /* Kon speaks twice on an Inn screen: this story line, then the request in
   * the bubble below. Two differently-styled boxes read as two speakers, so
   * this is aligned to the speech column and given the same paper as the
   * bubble - one voice, two lines, the earlier one quieter. */
  /* An episode leaves this empty, and an empty paper box still drew a bar
   * above Kon with nothing in it. */
  .inn-stage .narration:empty{display:none}
  .inn-stage .narration{margin:0 0 7px;padding:7px 10px;border:2px solid rgba(156,95,48,.5);border-radius:10px;background:rgba(255,250,240,.86);color:#4a3423;font-style:normal;font-size:.75rem}
  .inn-stage .romaji-toggle{position:absolute;right:10px;top:8px;margin:0;color:#f1dfbd;font-size:.65rem}
  .inn-stage .dialogue.entrance-dialogue{position:relative;display:grid;grid-template-columns:minmax(88px,118px) minmax(0,1fr);gap:7px;align-items:end;margin:0;padding:0;background:transparent;box-shadow:none}
  .inn-stage .dialogue.entrance-dialogue::before{content:"コン (Kon)";position:absolute;left:116px;top:-29px;z-index:2;padding:4px 10px;border:2px solid #8c562d;border-radius:8px 8px 0 0;background:#5a321d;color:#ffe8b8;font-family:'Shippori Mincho',serif;font-size:.68rem;font-weight:800}
  /* A guest or the 女将 speaking gets their own name on the tab (set from the
     line by app.js), rather than Kon's. */
  .inn-stage .dialogue.entrance-dialogue[data-speaker]::before{content:attr(data-speaker)}
  .inn-stage .dialogue.entrance-dialogue[data-dialogue-role="guest"]::before{border-color:#6f9792;background:#315b59;color:#f4fffa}
  .inn-stage .dialogue.entrance-dialogue .avatar.avatar-animated{width:118px;height:148px;align-self:end;filter:drop-shadow(0 8px 6px rgba(0,0,0,.38))}
  #screen-game.inn-stage .dialogue #avatar-slot.dialogue-guest-avatar{display:grid;place-items:end center}
  .inn-stage .dialogue .dialogue-guest-avatar > .shift-face{width:104px;height:104px;border-width:3px;box-shadow:0 7px 14px rgba(0,0,0,.34)}
  .inn-stage .dialogue.entrance-dialogue .speech{grid-column:2;min-height:148px;padding:13px 34px 11px 12px;border:2px solid rgba(156,95,48,.82);border-radius:11px;background:linear-gradient(180deg,#fffaf0,#eeddb8);color:#2d2926;box-shadow:0 5px 0 rgba(38,20,13,.8)}
  .inn-stage .dialogue.entrance-dialogue[data-dialogue-role="guest"] .speech{border-color:rgba(72,116,112,.88);background:linear-gradient(180deg,#f7fff9,#dcece5)}
  .inn-stage .speak-btn{position:absolute;right:8px;bottom:10px;margin:0;color:#5c3824}
  .inn-stage .listen-again{position:absolute;right:40px;bottom:11px;z-index:3}
  /* The button floats over the bubble, so the bubble has to stop short of it.
     Without this it sat on top of the last line of Kon's speech - worst in a
     narrow bubble, where her line wraps to five or six rows. */
  .inn-stage .dialogue:has(.listen-again:not([hidden])) .speech{padding-bottom:46px}
  .inn-stage .answer-workspace{grid-column:5/-1;grid-row:2;position:relative;align-self:end;min-width:0;min-height:0;padding:0;border:0;border-radius:13px;background:transparent;box-shadow:none}
  .inn-stage .answer-workspace .scene{min-width:0}
  .inn-stage .inn-focus-cue:not([hidden]){display:flex;align-items:center;gap:7px;width:max-content;max-width:100%;margin:0 0 7px;padding:5px 10px 5px 6px;border:1px solid rgba(230,178,96,.62);border-radius:999px;background:rgba(44,24,14,.88);box-shadow:0 3px 9px rgba(0,0,0,.24);color:#fff0cf;font-size:.68rem;font-weight:800;letter-spacing:.02em;line-height:1.15}
  .inn-stage .inn-focus-number{display:grid;place-items:center;width:19px;height:19px;border-radius:50%;background:#e2a44f;color:#3f2112;font-family:'Shippori Mincho',serif;font-size:.8rem;font-weight:900}
  .inn-stage .inn-focus-read{align-self:flex-start}
  .inn-stage .inn-focus-answer{margin-left:2px}

  /* Feedback and the continuation button must never be the reason the page
   * grows past the viewport - but a content-heavy room (the arrange task's
   * thirteen objects, say) must not be squeezed into a cramped, always-
   * scrolling box just because a *different* moment (feedback appearing)
   * needs protecting. Those are different problems and this fix used to
   * solve them with the same always-on cap, which is what made every visit
   * to a tall room scroll from the very first frame, before any answer.
   *
   * #feedback-row and #next-row are plain children of .answer-workspace,
   * stacked below #scene. Uncapped, a grid row sized with minmax(0,1fr) only
   * tracks its content: a correct answer added a feedback bar's worth of
   * height, the row grew to fit it, and the whole page grew with the row -
   * measured at 795px before an answer and 873px after, on a 768px-tall
   * viewport, with the result and the continue button below the fold on the
   * shift they were most needed for.
   *
   * The fix is scoped to exactly that moment with :has(): only once
   * #feedback-row actually carries .show does .game-layout get a fixed
   * height (equal to its own pre-existing min-height, so nothing about a
   * quiet room's normal size changes), which is what lets minmax(0,1fr)
   * divide the space it is given instead of growing to fit its content.
   * Before feedback, .game-layout keeps only its ordinary min-height and is
   * free to grow as tall as the room needs, exactly as it could before this
   * fix existed.
   *
   * Inside that now-fixed row, .answer-workspace becomes a column where the
   * answered scene is the part allowed to shrink and scroll, while the
   * feedback bar and the continue button stay full size and always in view.
   * flex/overflow on .scene are left unconditional - with no max-height on
   * .game-layout they are no-ops, since a flex item with no height ceiling
   * on its container just lays out at its natural size. Scoped to wider
   * layouts only - the room already reflows completely differently below
   * 760px, and is not where either report was made. */
  @media(min-width:761px){
    .inn-stage .answer-workspace{display:flex;flex-direction:column;max-height:100%}
    .inn-stage .answer-workspace .scene{flex:1 1 auto;min-height:0;overflow-y:auto}
    /* .scene is a plain block, so growing it via flex:1 above just gives a
       reply or word-choice list a taller box to sit at the top of - the gap
       this was meant to fix moved one level down instead of closing. This is
       the layer that actually had it: centering .answer-workspace alone did
       nothing here, since .scene (not .answer-workspace) is what claims the
       leftover height at this width. */
    .inn-stage .answer-workspace .scene:has(.inn-replies){display:flex;flex-direction:column;justify-content:center}
    .inn-stage .answer-workspace #feedback-row,
    .inn-stage .answer-workspace #next-row{flex:0 0 auto}
    .inn-stage .game-layout:has(.answer-workspace #feedback-row.show){
      max-height:calc(min(690px,100svh - 64px) - 28px);
    }
  }
  .inn-stage .inn-instruction{position:relative;margin:0 0 8px;padding:17px 10px 6px;border:1px solid rgba(203,145,85,.34);border-radius:9px;background:rgba(38,22,14,.55);color:#e3d0ad;font-size:.72rem}
  .inn-stage .inn-instruction::before{content:"HOW TO INTERACT";position:absolute;left:10px;top:4px;color:#9a5f30;font-size:.56rem;font-weight:900;letter-spacing:.13em}
  .inn-stage .inn-instruction-jp{display:block;margin:1px 0 3px;color:#fff0cf;font-family:'Shippori Mincho',serif;font-size:.9rem;line-height:1.35}
  .inn-stage .inn-new-word{display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:9px;align-items:center;margin:0 0 8px;padding:9px 12px;border:2px solid rgba(156,95,48,.85);border-left:5px solid #c8862f;border-radius:9px;background:linear-gradient(180deg,#fffaf0,#f0dfba);box-shadow:0 4px 12px rgba(0,0,0,.28);color:#3d2a1b}
  .inn-stage .inn-new-word-kicker{grid-column:1/-1;color:#9a5f30;font-size:.57rem;font-weight:900;letter-spacing:.14em}
  .inn-stage .inn-new-word b{font-family:'Shippori Mincho',serif;font-size:1.5rem;line-height:1.1}
  .inn-stage .inn-new-word-reading{color:#6d4a2a;font-size:.7rem}
  .inn-stage .inn-new-word-meaning{grid-column:1/-1;color:#4a3423;font-size:.74rem}
  .inn-stage .inn-shift-progress{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:3px;margin:0 0 8px;padding:7px 9px;list-style:none;border:1px solid rgba(205,151,86,.68);border-radius:9px;background:rgba(57,31,20,.82);box-shadow:inset 0 1px rgba(255,230,182,.14)}
  .inn-stage .inn-shift-beat{display:grid;justify-items:center;gap:2px;min-width:0;color:#ceb79a;font-size:.58rem;line-height:1.1;text-align:center}
  .inn-stage .inn-shift-beat span{width:8px;height:8px;border:1px solid #d39b55;border-radius:50%;background:rgba(255,243,214,.14)}
  .inn-stage .inn-shift-beat.is-done{color:#f7dfab}.inn-stage .inn-shift-beat.is-done span{background:#efb95d}
  .inn-stage .inn-shift-beat.is-current{color:#fff2d2}.inn-stage .inn-shift-beat.is-current span{background:#ffe1a0;box-shadow:0 0 0 3px rgba(246,190,98,.24)}
  .inn-stage .inn-clue{margin-bottom:8px;border-left-color:#c18c4f;background:#f3ead3;color:#493827;font-size:.78rem}
  .inn-stage .inn-room-composite{border-color:#8c562d;box-shadow:0 8px 18px rgba(0,0,0,.34)}
  .inn-stage .hint-btn{color:#f1dfbd}
  .inn-stage .hint-box.show,.inn-stage .feedback-row{background:#f2e5c8;color:#493827}

  @media(max-width:760px){
    #screen-game.inn-stage{min-height:0;padding:10px}
    .inn-stage .game-layout{grid-template-columns:1fr;grid-template-rows:auto auto auto;gap:9px}
    .inn-stage .stage-bar{grid-column:1;grid-row:1;margin:0;padding:8px 10px}
    .inn-stage .learning-context{display:block;grid-column:1;grid-row:2;padding:16px 8px 8px;border:0;background:transparent}
    .inn-stage .answer-workspace{grid-column:1;grid-row:3;padding:0}
    .inn-stage .narration{font-size:.7rem;line-height:1.35}
    .inn-stage .dialogue.entrance-dialogue{position:relative;top:auto;grid-template-columns:70px minmax(0,1fr);padding:0;background:transparent;box-shadow:none}
    .inn-stage .dialogue.entrance-dialogue::before{left:68px;top:-25px;font-size:.62rem}
    .inn-stage .dialogue.entrance-dialogue .avatar.avatar-animated{width:70px;height:88px}
    .inn-stage .dialogue .dialogue-guest-avatar > .shift-face{width:66px;height:66px}
    .inn-stage .dialogue.entrance-dialogue .speech{min-height:88px;padding:9px 32px 8px 10px}
    .inn-stage .jp-line{font-size:1rem;line-height:1.35}
    .inn-stage .romaji-line{font-size:.72rem}
    .inn-stage .inn-instruction{font-size:.72rem}
    .inn-stage .inn-focus-cue:not([hidden]){margin-bottom:6px;font-size:.65rem}
    .inn-stage .inn-new-word{margin-bottom:7px;padding:6px 8px}
    .inn-stage .inn-shift-progress{padding:6px 7px}
    .inn-journey{padding-top:5px}
    .inn-journey-status{margin-bottom:3px;font-size:.6rem}
    .inn-journey-stops{gap:2px}
    .inn-journey-stop{grid-template-columns:9px minmax(0,1fr);column-gap:2px;padding:3px}
    .inn-journey-lamp{width:7px;height:7px}
    .inn-journey-label{font-size:.68rem}
    .inn-journey-reward{display:none}
    .inn-reward{padding:18px 13px 15px;border-radius:12px}
    .inn-reward-image{width:min(128px,48%);max-height:108px}
    .inn-reward h2{font-size:1.3rem}
    .inn-stage .inn-room-composite{width:100%;margin:0}
    .inn-stage .next-row{margin-left:-7px;margin-right:-7px}

  }

  @media(prefers-reduced-motion:reduce){
    .inn-journey-stop.is-current .inn-journey-lamp,
    .inn-reward,.inn-reward-image,.inn-reward-spark{animation:none!important;transform:none}
  }

  /* Episode openings use the same bottom-dock composition as the Entrance.
     The earlier narrow speech column plus a floating paper card made two
     unrelated boxes hover over the room. These two panels now share one
     baseline, material and visual weight while the inn remains visible. */
  .inn-stage .game-layout:has(.episode-open){grid-template-columns:repeat(12,minmax(0,1fr));align-items:end}
  .inn-stage .game-layout:has(.episode-open) .learning-context{
    grid-column:1/8;min-height:226px;padding:34px 10px 10px;
    border:2px solid #8c562d;background:rgba(58,31,20,.86);
    backdrop-filter:blur(9px) saturate(115%);
    box-shadow:inset 0 1px rgba(244,202,128,.2),0 8px 22px rgba(0,0,0,.36)
  }
  .inn-stage .answer-workspace:has(.episode-open){
    grid-column:8/-1;min-height:226px;padding:10px;
    border:2px solid #8c562d;background:rgba(58,31,20,.86);
    backdrop-filter:blur(9px) saturate(115%);
    box-shadow:inset 0 1px rgba(244,202,128,.2),0 8px 22px rgba(0,0,0,.36)
  }
  .inn-stage .answer-workspace:has(.episode-open) .scene{height:100%}
  .inn-stage .episode-open{min-height:204px;height:100%;padding:0}
  .inn-stage .episode-open-card{
    display:grid;align-content:center;width:100%;max-width:none;min-height:204px;padding:18px 22px;
    border:2px solid rgba(184,119,63,.82);border-radius:10px;
    background:rgba(249,238,211,.94);box-shadow:0 4px 0 rgba(35,20,13,.72)
  }
  /* A word being taught gets the whole width.
     Reported from play: Kon's panel took seven of the twelve columns while
     the card being studied had five, and her line there is one generic
     sentence - "let us learn this word" - repeated on every card. It is the
     one screen in the stage with nothing to read on the left, so the left is
     gone and the card is the screen. The badge still says あたらしい言葉, and
     the first card carries the instruction itself. */
  .inn-stage .game-layout:has(.teach-card){grid-template-columns:1fr}
  .inn-stage .game-layout:has(.teach-card) .learning-context{display:none}
  .inn-stage .answer-workspace:has(.teach-card){grid-column:1/-1}
  /* Capped and centred: full width on a phone, but a sentence set across a
     desktop monitor is a worse line to read, not a better one. */
  .inn-stage .episode-open-card.teach-card{max-width:640px;margin-inline:auto;padding:26px 28px}
  .inn-stage .teach-word{font-size:2.6rem}
  .inn-stage .teach-sentence{font-size:1.25rem}
  .inn-stage .episode-open-title{font-size:1.2rem}
  .inn-stage .episode-open-card .btn{min-width:168px;margin-inline:auto}

  @media(max-width:760px){
    .inn-stage .game-layout:has(.episode-open){grid-template-columns:1fr;grid-template-rows:auto auto auto;align-items:stretch}
    .inn-stage .game-layout:has(.episode-open) .learning-context{grid-column:1;grid-row:2;min-height:0;padding:28px 7px 7px}
    /* Same on a phone, where the panel is a screen of its own to scroll past
       before reaching the word. */
    .inn-stage .game-layout:has(.teach-card){grid-template-rows:auto auto}
    .inn-stage .game-layout:has(.teach-card) .learning-context{display:none}
    .inn-stage .answer-workspace:has(.teach-card){grid-row:2}
    .inn-stage .episode-open-card.teach-card{padding:18px 16px}
    .inn-stage .teach-word{font-size:2.1rem}
    .inn-stage .teach-sentence{font-size:1.12rem}
    .inn-stage .answer-workspace:has(.episode-open){grid-column:1;grid-row:3;min-height:0;padding:7px}
    .inn-stage .episode-open,.inn-stage .episode-open-card{min-height:150px}
    .inn-stage .episode-open-card{padding:12px 14px}
  }

  .inn-room{position:relative;min-height:310px;overflow:hidden;border:1px solid #c9b88d;border-radius:18px;background:linear-gradient(#eee4c8 0 58%,#c8b77c 58%);box-shadow:inset 0 0 55px rgba(92,67,31,.12)}
  .inn-room:before{content:"";position:absolute;inset:58% 0 0;background:repeating-linear-gradient(90deg,transparent 0 31%,rgba(75,64,35,.13) 31% 31.5%),repeating-linear-gradient(0deg,transparent 0 48%,rgba(75,64,35,.1) 48% 49%)}
  .shoji{position:absolute;top:18px;right:22px;width:128px;height:136px;border:7px solid #674c35;background:repeating-linear-gradient(90deg,#f7f1df 0 30px,#9b7855 30px 34px);box-shadow:inset 0 0 0 2px #dfd2b5}
  .inn-workspace{position:relative;z-index:1;min-height:310px;padding:18px;display:flex;flex-direction:column;justify-content:flex-start;gap:12px}
  .inn-content{display:flex;flex-direction:column;gap:12px}
  .inn-content:empty{display:none}
  .inn-instruction{margin:0 0 8px;padding:8px 12px;border-radius:12px;background:#fffcf2;border:1px solid rgba(27,42,74,.12);color:#493827;font-size:.84rem;font-weight:700;line-height:1.35}
  .inn-clue{padding:8px 12px;margin-bottom:12px;border-left:4px solid #8da486;border-radius:0 10px 10px 0;background:#f4f8eb;color:#40503d;line-height:1.4;font-size:.84rem}
  details.inn-clue summary{cursor:pointer;font-weight:700;list-style-position:inside}
  details.inn-clue span{display:block;margin-top:6px}
  .inn-actions,.inn-targets{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:10px}
  .inn-object,.inn-action,.inn-drop-zone{min-width:58px;min-height:58px;border:2px solid #9d7d50;border-radius:14px;background:#fffaf0;color:#3e3024;font:inherit;font-weight:700;cursor:pointer;box-shadow:0 5px 0 #80643f;transition:transform .16s,box-shadow .16s,background .16s;display:flex;align-items:center;justify-content:center;padding:8px}
  .inn-icon{position:relative;width:32px;height:32px;color:#493827}
  .inn-icon svg{width:100%;height:100%;stroke:currentColor;fill:none;stroke-width:2.1;stroke-linecap:round;stroke-linejoin:round}
  .inn-object,.inn-action,.inn-drop-zone{flex-direction:column;gap:4px}
  .inn-object:has(.inn-caption),.inn-action:has(.inn-caption),.inn-drop-zone:has(.inn-caption){min-width:110px;min-height:76px;padding:10px 12px}
  .inn-caption{font-size:.78rem;font-weight:700;line-height:1.3;max-width:16ch;text-align:center}
  .inn-scene-zones{align-self:stretch;display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:10px;padding:14px;border-radius:14px;background:rgba(255,250,240,.5);border:1px dashed rgba(120,95,60,.45)}
  .inn-scene-zones:empty{display:none}
  .inn-replies{flex-direction:column;align-items:stretch;gap:8px}
  .answer-workspace .inn-replies{width:100%;max-width:none}
  .inn-replies .reply-option{flex-direction:row;justify-content:flex-start;gap:10px;min-height:0;padding:10px 14px;text-align:left}
  .inn-replies .reply-option .inn-caption{max-width:none;text-align:left;font-size:.9rem}
  .mat-zone{min-height:84px;align-items:center;justify-content:center;background:rgba(200,183,124,.32);border-color:#a08a5c}
  .mat-items{display:flex;flex-wrap:wrap;gap:6px;align-items:center;justify-content:center;min-height:34px}
  .cushion-icon svg{stroke:none}
  .inn-room-illustrated .cushion-icon{width:88%;height:88%;filter:drop-shadow(0 3px 2px rgba(38,26,18,.34))}
  .inn-room-illustrated .mat-items .cushion-icon{width:48%;height:auto;aspect-ratio:1;flex:0 0 auto}
  .inn-floor-label{grid-column:1/-1;font-size:.7rem;letter-spacing:.08em;text-transform:uppercase;color:#8e5c32;text-align:center}
  .inn-drop-zone{border-style:dashed;background:rgba(255,250,240,.55);position:relative}
  .inn-drop-zone.drop-hover{background:#ffe9c2;border-color:#e8963c;transform:scale(1.04)}
  .inn-drop-zone.filled{border-style:solid;background:rgba(220,233,216,.85)}
  .inn-drop-zone:disabled{opacity:.5;cursor:not-allowed}
  .inn-tray{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;align-self:stretch;position:relative;z-index:1}
  .inn-object.dragging{position:fixed;z-index:1000;opacity:.98;box-shadow:0 14px 24px rgba(0,0,0,.28);cursor:grabbing}
  /* Tap-to-place: the chosen object lifts, and the places it can go pulse. */
  .inn-object.selected{background:#ffe0a3;border-color:#d08d38;box-shadow:0 0 0 3px rgba(208,141,56,.35),0 6px 0 #80643f;transform:translateY(-3px)}
  .inn-scene-zones.awaiting-drop .inn-drop-zone{border-color:#d08d38;background:#fffdf6;animation:zone-ready 1.4s ease-in-out infinite}
  @keyframes zone-ready{50%{box-shadow:0 0 0 4px rgba(208,141,56,.22)}}
  @media(prefers-reduced-motion:reduce){.inn-scene-zones.awaiting-drop .inn-drop-zone{animation:none;box-shadow:0 0 0 3px rgba(208,141,56,.25)}}
  @media(prefers-reduced-motion:reduce){.inn-drop-zone{transition:none}}
  .inn-object:hover,.inn-action:hover,.inn-drop-zone:hover,.inn-object:focus-visible,.inn-action:focus-visible,.inn-drop-zone:focus-visible{transform:translateY(-2px);outline:3px solid #d08d38;outline-offset:2px}
  .inn-drop-zone:has(.inn-object){transform:none}
  .inn-object.selected{background:#ffe0a3;box-shadow:0 2px 0 #80643f;transform:translateY(3px)}
  .tea-visual{align-self:center;position:relative;min-width:150px;padding:18px 22px 12px;border-radius:50% 50% 18px 18px;background:rgba(255,250,240,.84);text-align:center}
  .tea-food{display:block;font-size:4.2rem;line-height:1.1;filter:saturate(.65)}
  .tea-state{display:block;min-height:24px;margin-top:5px;font-weight:800;color:#536d78}
  .tea-steam{position:absolute;left:50%;top:-8px;width:70px;height:48px;transform:translateX(-50%);opacity:0}
  .tea-steam:before,.tea-steam:after{content:"~";position:absolute;font-size:2rem;color:#eef7f5;animation:steam 1s ease-in-out infinite}
  .tea-steam:before{left:8px}.tea-steam:after{right:8px;animation-delay:.3s}
  .tea-visual.ready .tea-steam{opacity:.8}
  .tea-visual.ready .tea-food{filter:saturate(1)}
  @keyframes steam{50%{transform:translateY(-8px)}}
  /* user-select:none because dragging the range inputs just below this row
     could catch the hour labels in a native text selection, which drew as a
     stray highlighted box over whichever label the drag passed through. */
  .schedule-timeline{display:grid;grid-template-columns:repeat(6,1fr);gap:4px;padding:12px;border-radius:14px;background:rgba(255,250,240,.8);user-select:none}
  .schedule-timeline span{text-align:center;font-size:.82rem;color:#6c5a46}
  .schedule-controls{display:grid;grid-template-columns:1fr 1fr;gap:12px;user-select:none}
  .answer-workspace .schedule-controls{width:100%;align-self:stretch}
  .schedule-time-card{padding:10px;border:1px solid rgba(140,86,45,.3);border-radius:12px;background:#fffaf0;color:#493827}
  .schedule-time-card h3{margin:0 0 8px;color:#5c3824;font-size:.86rem;line-height:1.25}
  .schedule-stepper{display:grid;grid-template-columns:minmax(62px,1fr) auto minmax(62px,1fr);align-items:center;gap:6px}
  .schedule-step{min-height:40px;padding:6px 8px;border:1px solid #946033;border-radius:9px;background:#f7e4bd;color:#4a2d18;font:inherit;font-size:.7rem;font-weight:900;line-height:1.1;cursor:pointer;box-shadow:0 2px 0 #80512c}
  .schedule-step:hover{background:#fff1cf;transform:translateY(-1px)}
  .schedule-step:active{transform:translateY(1px);box-shadow:none}
  .schedule-step:focus-visible{outline:3px solid var(--lantern-bright);outline-offset:2px}
  .schedule-step:disabled{opacity:.45;cursor:not-allowed;transform:none;box-shadow:none}
  .schedule-stepper output,.schedule-time-card > output{min-width:61px;color:#4a2d18;font-size:1rem;font-weight:900;text-align:center;white-space:nowrap}
  .schedule-time-card.is-fixed{background:#f0e6d4;color:#6c5a46}
  .schedule-fixed{display:block;color:#765d45;font-size:.71rem;font-weight:800;text-align:center}
  .inn-status{text-align:center;min-height:24px;font-weight:800;color:#f2ddb6}
  .medal{margin-left:5px;font-size:1.05rem}
  .inn-drop-zone:disabled,.inn-object:disabled{opacity:.35;cursor:not-allowed;box-shadow:none;transform:none}
  .answer-workspace .inn-room,.answer-workspace .inn-workspace{min-height:0}
  .answer-workspace .inn-workspace{padding:12px;gap:8px}
  .answer-workspace .inn-scene-zones{grid-template-columns:repeat(auto-fit,minmax(104px,1fr));gap:8px;padding:10px}
  .answer-workspace .inn-object:has(.inn-caption),.answer-workspace .inn-action:has(.inn-caption),.answer-workspace .inn-drop-zone:has(.inn-caption){min-width:0;min-height:64px;padding:7px 9px}
  .answer-workspace .inn-icon{width:26px;height:26px}
  .answer-workspace .inn-caption{font-size:.72rem;max-width:13ch}
  .answer-workspace .inn-tray{gap:8px}
  /* Objects sitting in a zone flow above its caption. They used to be
     absolutely positioned at the top-right, which covered the label:
     "タオル掛け" rendered as "タオル…" with the icon on top of it. */
  .inn-drop-zone > .inn-placed-object{position:static;top:auto;right:auto;flex:0 0 auto}
  span.inn-placed-object{display:inline-flex;align-items:center;justify-content:center;padding:0;border:0;background:transparent;box-shadow:none;min-width:0;min-height:0}
  button.inn-placed-object{min-width:0;min-height:0;padding:5px;box-shadow:0 2px 0 #80643f}
  .answer-workspace .inn-drop-zone > .inn-placed-object{width:auto;height:auto;min-width:0;min-height:0}
  .answer-workspace button.inn-placed-object{padding:5px}
  /* A zone holding an object needs room for both it and the caption. */
  .answer-workspace .inn-drop-zone:has(.inn-placed-object){min-height:96px}
  .answer-workspace .inn-room:has(.inn-replies){min-height:0;background:transparent;border:0;box-shadow:none;overflow:visible}
  .answer-workspace .inn-room:has(.inn-replies):before{display:none}
  .answer-workspace .inn-room:has(.inn-replies) .inn-workspace{min-height:0;padding:0}
  /* A reply or word-choice screen is a short list of words, not a room, and
     it was laid out as though it were one: the answers stretched the full
     eight-column width, so 「揃って」 sat inside an 850px banner, while the
     question that actually has to be read was squeezed into a 224px bubble
     in the opposite corner and wrapped four times. Two changes, one idea -
     give the width to the text that needs it:
       - the columns split evenly for these screens, so the speech bubble
         gets ~400px instead of ~224px and the request reads in two lines;
       - the answers are capped to a readable measure and centred, so they
         read as choices rather than as full-bleed bars.
     Room tasks have no .inn-replies and keep the wide answer column they
     genuinely use for the illustrated room. */
  /* Gated to the two-column layout, and it has to be: these place children
     into columns 1-7 and 7-13 of a twelve-column grid, but the mobile rule
     above collapses that grid to a single 1fr track. A grid-column of 1/7
     against one explicit track does not clamp - it creates five implicit
     columns to reach seven lines. The bar was then handed the first of them,
     24px wide, and every label in it wrapped one character per line down the
     left edge of the phone. Reported from a phone, at 360px; the 375px
     preset was fifteen pixels too wide to show it. */
  @media(min-width:761px){
    .inn-stage .game-layout:has(.inn-replies) .learning-context{grid-column:1/7}
    .inn-stage .game-layout:has(.inn-replies) .answer-workspace{grid-column:7/-1}
  }
  .inn-stage .answer-workspace .scene:has(.inn-replies){align-items:center}
  .inn-stage .answer-workspace .scene:has(.inn-replies) > *{width:min(480px,100%)}
  /* A short reply list or a word-choice question is only a few lines of
     text, but .answer-workspace itself sizes to that short content and then
     sits align-self:end against whatever the room-task column next to it
     needs - a kitchen scene plus a room's worth of objects. The result was
     the whole card pinned to the bottom of a much taller row, with a bare
     gap above it reading as unfinished layout rather than a deliberate
     composition. Centering the workspace within the full row height it is
     actually given fixes that without touching object-room tasks, which
     have no .inn-replies and are unaffected by this selector. */
  .inn-stage .answer-workspace:has(.inn-replies){align-self:stretch;display:flex;flex-direction:column;justify-content:center}

  /* Keep the two numbered actions in one reading band on desktop. The grid
     row is often taller than a short question, so bottom/centre alignment
     left hundreds of empty pixels above Kon and the answer controls. The
     episode opening also opts out of inherited bottom placement so Kon does
     not sit below a tall blank wall. */
  @media(min-width:761px){
    .inn-stage .learning-context{justify-content:flex-start}
    .inn-stage .answer-workspace{align-self:start}
    .inn-stage .game-layout:has(.episode-open) .learning-context{align-self:start}
    .inn-stage .answer-workspace:has(.inn-replies){justify-content:flex-start}
    .inn-stage .answer-workspace .scene:has(.inn-replies){justify-content:flex-start}
  }

  /* Illustrated room: fixtures live in the background; answer objects do not. */
  .inn-room-illustrated{min-height:0;overflow:visible;border:0;background:transparent;box-shadow:none}
  .inn-room-illustrated:before{display:none}
  .inn-room-illustrated .inn-workspace{min-height:0;padding:0;gap:10px}
  .inn-room-composite{display:flex;flex-direction:column;position:relative;width:100%;overflow:hidden;border:1px solid #6e4c2f;border-radius:16px;background:#b89562;box-shadow:0 10px 24px rgba(46,31,20,.2)}
  .inn-room-viewport{position:relative;width:100%;aspect-ratio:3/2;overflow:hidden;border:1px solid #6e4c2f;border-radius:16px;background:#b89562;box-shadow:0 10px 24px rgba(46,31,20,.2)}
  .inn-room-composite > .inn-room-viewport{border:0;border-radius:0;box-shadow:none}
  .inn-room-art{position:absolute;inset:0;z-index:0;width:100%;height:100%;display:block;object-fit:cover;pointer-events:none;user-select:none}
  .inn-room-viewport::before,.inn-room-viewport::after{content:"";position:absolute;inset:0;z-index:1;opacity:0;pointer-events:none}
  .inn-room-viewport::before{background:rgba(7,15,29,.48);transition:opacity .5s cubic-bezier(.22,1,.36,1)}
  .inn-room-viewport::after{background:radial-gradient(circle at 50.5% 22%,rgba(255,226,143,.72) 0,rgba(248,188,82,.34) 9%,rgba(248,177,60,.08) 24%,transparent 42%)}
  .room-light-dim::before{opacity:1}
  .room-light-bright::after{animation:room-light-warm .65s cubic-bezier(.22,1,.36,1) forwards}
  @keyframes room-light-warm{0%{opacity:.95}48%{opacity:.58}100%{opacity:.22}}
  .inn-room-illustrated .inn-scene-zones{position:absolute;inset:0;z-index:2;display:block;padding:0;border:0;border-radius:0;background:transparent}
  .inn-room-illustrated .inn-scene-zones:empty{display:block}
  .inn-hotspot{position:absolute;min-width:44px;min-height:44px;padding:2px;border:2px solid transparent;border-radius:12px;background:rgba(255,250,240,.04);box-shadow:none;overflow:visible;isolation:isolate}
  .answer-workspace .inn-room-illustrated .inn-hotspot:has(.inn-caption){min-width:0;min-height:0;padding:2px}
  .inn-room-illustrated .mat-zone{border:3px solid rgba(58,67,35,.92);background:linear-gradient(rgba(221,191,116,.12),rgba(221,191,116,.12)),repeating-linear-gradient(90deg,rgba(239,210,137,.24) 0,rgba(239,210,137,.24) 2px,rgba(79,82,43,.12) 2px,rgba(79,82,43,.12) 4px);box-shadow:inset 0 0 0 2px rgba(255,238,180,.38),0 0 0 2px rgba(42,48,26,.35)}
  .inn-room-illustrated .mat-zone:after{content:"";position:absolute;inset:5px;border:2px solid rgba(65,73,38,.64);border-radius:7px;pointer-events:none}
  .inn-hotspot:hover,.inn-hotspot:focus-visible{transform:none;border-color:#f4bd66;background:rgba(255,246,221,.18);outline:3px solid rgba(83,49,23,.55);outline-offset:1px}
  .inn-room-illustrated .inn-scene-zones.awaiting-drop .inn-hotspot{border-color:#f0a94d;background:rgba(255,238,191,.2);box-shadow:0 0 0 3px rgba(240,169,77,.23);animation:zone-ready 1.4s ease-in-out infinite}
  .inn-supply-shelf{position:relative;padding:12px;border:2px solid #6c4529;border-radius:14px;background:linear-gradient(180deg,#9a6840,#71472d);box-shadow:inset 0 0 0 3px rgba(255,224,175,.13),0 7px 14px rgba(48,31,20,.2)}
  .inn-room-composite > .inn-supply-shelf{padding:10px 12px 12px;border:0;border-top:8px solid #4d301d;border-radius:0;background:linear-gradient(180deg,#a97649 0,#855535 24%,#684028 100%);box-shadow:inset 0 4px 0 rgba(255,224,175,.16),inset 0 -3px 0 rgba(45,27,16,.3)}
  .inn-room-illustrated .inn-tray{display:grid;grid-template-columns:repeat(10,minmax(44px,1fr));justify-content:center;gap:4px;width:100%;align-items:center}
  .inn-room-illustrated .inn-object{position:relative;width:100%;min-width:0;min-height:44px;aspect-ratio:1;padding:3px;border:1px solid rgba(255,244,224,.45);border-radius:10px;background:rgba(255,250,240,.12);box-shadow:0 3px 0 rgba(55,34,20,.6);overflow:hidden}
  .inn-room-illustrated .inn-object:hover,.inn-room-illustrated .inn-object:focus-visible{transform:translateY(-3px);background:rgba(255,246,225,.3)}
  .inn-room-illustrated .inn-object.selected{transform:translateY(-3px);border-color:#f6c66f;background:rgba(255,225,166,.44);box-shadow:0 0 0 3px rgba(246,198,111,.38),0 4px 0 rgba(55,34,20,.6)}
  .inn-room-illustrated .inn-object.dragging{position:fixed;z-index:1000;transform:none}
  .inn-sprite{display:block;width:100%;height:100%;background-image:var(--inn-sprite-sheet);background-repeat:no-repeat;background-size:400% 400%;background-position:calc(var(--sprite-col) * 33.333333%) calc(var(--sprite-row) * 33.333333%);filter:drop-shadow(0 3px 2px rgba(38,26,18,.28));pointer-events:none}
  .inn-photo-sprite{display:block;width:100%;height:100%;object-fit:contain;filter:drop-shadow(0 3px 2px rgba(38,26,18,.28));pointer-events:none}
  .inn-room-illustrated .inn-object .inn-sprite{transform:scale(1.2)}
  .inn-room-illustrated .inn-sprite-c1,.inn-room-illustrated .inn-sprite-c2,.inn-room-illustrated .inn-sprite-c3,.inn-room-illustrated .inn-sprite-c4{transform:rotate(var(--sprite-rotate)) scale(var(--sprite-zoom))}
  .inn-room-illustrated .inn-sprite-bulbBroken,.inn-room-illustrated .inn-sprite-bulbNew{transform:scale(1.38)}
  .inn-room-illustrated .inn-sprite-towelUsed,.inn-room-illustrated .inn-sprite-towelClean{transform:scale(1.26)}
  .inn-room-illustrated .inn-photo-sprite-sheetStained{-webkit-mask-image:var(--object-image);mask-image:var(--object-image);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center;-webkit-mask-size:contain;mask-size:contain;mask-mode:luminance;transform:translate(-12%,2%) rotate(-14deg) scale(1.18)}
  .inn-room-illustrated .inn-caption{position:absolute;left:50%;bottom:calc(100% + 5px);z-index:6;max-width:18ch;padding:4px 7px;border-radius:7px;background:rgba(39,28,20,.94);color:#fffaf0;font-size:.7rem;line-height:1.25;white-space:nowrap;opacity:0;transform:translate(-50%,4px);transition:opacity .14s ease,transform .14s ease;pointer-events:none}
  .inn-room-illustrated .inn-hotspot > .inn-caption{top:auto;bottom:calc(100% + 5px);transform:translate(-50%,4px)}
  .inn-room-illustrated [data-key="install-bulb"] > .inn-caption{top:calc(100% + 5px);bottom:auto}
  .inn-room-illustrated .inn-object:hover .inn-caption,.inn-room-illustrated .inn-object:focus-visible .inn-caption,.inn-room-illustrated .inn-object.selected .inn-caption,.inn-room-illustrated .inn-hotspot:hover > .inn-caption,.inn-room-illustrated .inn-hotspot:focus-visible > .inn-caption{opacity:1;transform:translate(-50%,0)}
  .inn-room-illustrated .mat-items{width:100%;height:100%;display:flex;align-items:center;justify-content:center;gap:1px;flex-wrap:nowrap}
  .inn-room-illustrated .mat-items .inn-sprite{width:48%;height:auto;aspect-ratio:1}
  .inn-room-illustrated .inn-placed-object{position:relative;width:min(78%,74px);height:auto;aspect-ratio:1;flex:0 0 auto}
  .answer-workspace .inn-room-illustrated .inn-drop-zone > .inn-placed-object{width:min(78%,74px);height:auto;min-width:0;min-height:0}
  /* A zone narrower than it is tall - the bulb's ceiling fixture is 11% of
     the room's width - lost its width floor here along with the height one,
     leaving a squeezed sliver too small to read or tap on mobile. Restore
     both, matching the height floor that already existed. */
  .answer-workspace .inn-room-illustrated .inn-drop-zone:has(.inn-placed-object){min-width:44px;min-height:44px}
  .inn-room-illustrated button.inn-placed-object{padding:2px;border:1px solid transparent;background:rgba(255,250,240,.08);box-shadow:none}
  .inn-room-illustrated [data-key="install-sheet"] .inn-placed-object{width:100%;max-width:145px;overflow:visible;background:transparent}
  .inn-room-illustrated .inn-heated-object{width:72%;max-width:74px}
  .inn-heat-waves{position:absolute;left:50%;top:2%;z-index:4;color:#fff5dc;font-size:1.25rem;font-weight:800;text-shadow:0 1px 5px #7f512d;transform:translateX(-50%);animation:steam 1s ease-in-out infinite;pointer-events:none}
  .inn-room-illustrated .inn-status{min-height:20px;padding:0 8px;color:#f2ddb6;font-size:.8rem}

  @media(max-width:620px){
    .schedule-controls{grid-template-columns:1fr}
    /* Let the room shrink to its content: a forced min-height pushed the
       destinations off-screen and made the reach even longer. */
    .inn-room,.inn-workspace{min-height:0}
    .inn-workspace{padding:12px;gap:10px}
    .shoji{width:70px;height:86px;top:10px;right:12px;opacity:.5}
    .inn-scene-zones{padding:10px;gap:8px;grid-template-columns:repeat(auto-fit,minmax(88px,1fr))}
    .inn-tray{gap:8px}
    .inn-object,.inn-drop-zone{min-width:0}
    .inn-object:has(.inn-caption),.inn-action:has(.inn-caption),.inn-drop-zone:has(.inn-caption){min-width:84px;min-height:66px;padding:8px}
    .inn-caption{font-size:.72rem;max-width:12ch}
    .inn-icon{width:26px;height:26px}
    .inn-room-illustrated .inn-workspace{padding:0;gap:8px}
    .inn-room-composite{border-radius:12px}
    .inn-room-illustrated .inn-content{order:3}
    .inn-room-illustrated .inn-status{order:4}
    .inn-hotspot{min-width:42px;min-height:42px;border-radius:9px}
    .inn-supply-shelf{padding:9px}
    .inn-room-illustrated .inn-tray{grid-template-columns:repeat(5,minmax(0,1fr));gap:7px}
    .inn-room-illustrated .inn-caption{font-size:.68rem;max-width:16ch}
  }
  @media(min-width:761px) and (max-height:800px){
    .answer-workspace .inn-room,.answer-workspace .inn-workspace{min-height:0}
    .answer-workspace .inn-workspace{padding:12px;gap:8px}
    .answer-workspace .inn-scene-zones{padding:9px;gap:7px}
    .answer-workspace .inn-object:has(.inn-caption),.answer-workspace .inn-action:has(.inn-caption),.answer-workspace .inn-drop-zone:has(.inn-caption){min-height:62px;padding:7px 9px}
    .answer-workspace .shoji{width:84px;height:92px;opacity:.55}
    .inn-room-illustrated .inn-workspace{padding:0}
    .inn-room-composite{width:min(100%,70vh);margin-inline:auto}
    .inn-room-viewport{width:100%;margin:0}
    .inn-room-illustrated .inn-object:has(.inn-caption),.inn-room-illustrated .inn-drop-zone:has(.inn-caption){min-height:0;padding:3px}
    .inn-stage .inn-new-word{grid-template-columns:auto auto auto minmax(0,1fr);align-items:baseline;gap:0 7px;margin-bottom:6px;padding:5px 8px}
    .inn-stage .inn-new-word-kicker{grid-column:auto;font-size:.52rem;white-space:nowrap}
    .inn-stage .inn-new-word b{font-size:1.28rem;white-space:nowrap}
    .inn-stage .inn-new-word-reading{font-size:.66rem;white-space:nowrap}
    .inn-stage .inn-new-word-meaning{grid-column:auto;min-width:0;overflow:hidden;color:#f4ead5;font-size:.66rem;text-overflow:ellipsis;white-space:nowrap}
    .inn-room-viewport{aspect-ratio:8/5}
    .inn-room-composite > .inn-supply-shelf{padding:6px 10px 8px;border-top-width:5px}
  }
  @media(prefers-reduced-motion:reduce){.inn-object,.inn-action,.inn-drop-zone{transition:none}.tea-steam:before,.tea-steam:after{animation:none}.inn-room-viewport::before{transition:none}.room-light-bright::after{animation:none;opacity:.22}}

/* Guest satisfaction bar — visible during episodes. */
.streak-badge{position:relative;display:inline-flex;align-items:center;align-self:center;padding:4px 11px;border-radius:999px;background:linear-gradient(180deg,#5a2f12,#3a1b09);border:1.5px solid #ffb43d;color:#ffd970;font-size:.86rem;font-weight:900;letter-spacing:.03em;line-height:1.15;white-space:nowrap;box-shadow:0 2px 8px rgba(0,0,0,.5),inset 0 1px rgba(255,226,166,.3)}
.streak-badge:empty{display:none}
.streak-pop{animation:streak-pop .34s cubic-bezier(.34,1.56,.64,1)}
.streak-reset{animation:streak-out .35s ease-in forwards}
.streak-bonus{position:absolute;left:50%;top:-22px;transform:translateX(-50%);color:#7ee07e;font-size:1.05rem;font-weight:900;text-shadow:0 2px 6px rgba(0,0,0,.6);pointer-events:none;animation:streak-coin 1.1s ease-out forwards}
@keyframes streak-pop{0%{transform:scale(.72)}60%{transform:scale(1.18)}100%{transform:scale(1)}}
@keyframes streak-out{to{opacity:0;transform:translateY(-4px) scale(.9)}}
@keyframes streak-coin{0%{opacity:0;transform:translate(-50%,4px) scale(.8)}25%{opacity:1;transform:translate(-50%,-6px) scale(1.15)}100%{opacity:0;transform:translate(-50%,-34px) scale(1)}}
@keyframes guest-sat-in{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}
.guest-sat-summary{text-align:center;padding:16px;display:flex;flex-direction:column;align-items:center;gap:6px}
.guest-sat-summary-face{font-size:2.8rem;line-height:1;animation:guest-sat-in .5s}
.guest-sat-summary-stars{font-size:1.4rem;letter-spacing:.2em;color:#ffd700;text-shadow:0 2px 4px rgba(0,0,0,.3)}
.guest-sat-summary-label{margin:0;font-size:1.1rem;font-weight:800;color:#3d2717}
.guest-sat-summary-msg{margin:0;color:#65462f;font-size:.84rem}
.guest-sat-summary-coins{margin:0;color:#8c4e1e;font-size:.88rem;font-weight:900;animation:guest-sat-in .6s}
.guest-sat-summary-streak{margin:0;color:#5a8a3e;font-size:.78rem;font-weight:700}

/* Question controls.
   Sized in em so they grow with the page text: at 200% zoom a px-sized button
   keeps its box while its label grows, which is how labels get clipped. */
.question-controls{display:flex; flex-wrap:wrap; gap:0.6em; align-items:stretch;}
.question-control{
  flex:1 1 auto; min-width:0;
  padding:0.7em 1.1em;
  border:2px solid #8c562d; border-radius:0.6em;
  background:linear-gradient(180deg,#fffaf0,#efe0be);
  color:#2d2926;
  font-family:inherit; font-size:1rem; line-height:1.4;
  text-align:left; white-space:normal; overflow-wrap:anywhere;
  cursor:pointer;
}
.question-control.is-primary{box-shadow:0 3px 0 rgba(55,30,18,.55);}
/* The typed answer. Built to sit in the same row as the option buttons and
   read as one of them, because it is the same question in a harder form: the
   same washi ground, the same wood border, the same corner. The field takes
   the row and the 答える button sits beside it, and on a phone they stack -
   a 44px minimum on both, since this is the one control in the game a
   learner touches with a keyboard already covering half the screen. */
.reading-input{
  flex:3 1 12em; min-width:0; min-height:44px;
  padding:0.7em 1.1em;
  border:2px solid #8c562d; border-radius:0.6em;
  background:#fffaf0;
  color:#2d2926;
  font-family:'Shippori Mincho',serif; font-size:1.15rem; line-height:1.4;
}
.reading-input::placeholder{color:#a8937a; font-family:'Zen Maru Gothic',sans-serif; font-size:.9rem;}
.reading-input:focus-visible{outline:3px solid var(--lantern); outline-offset:2px;}
.reading-input:disabled{background:#efe6d4; color:#6b5844;}
.question-control.reading-submit{flex:1 1 6em; text-align:center; white-space:nowrap;}
/* Answered, and visibly so: the button and the box grey together, because the
   learner's eye is on the box and a live-looking button beside a dead one
   invites a second press. */
.question-control:disabled{background:#efe6d4; color:#6b5844; border-color:#a98a6b; box-shadow:none; cursor:default;}
.question-control:focus-visible{outline:3px solid var(--lantern); outline-offset:2px;}
@media(max-width:760px){
  /* One per row on a phone: two long Japanese replies side by side wrap into
     unreadable columns. */
  .question-control{flex:1 1 100%;}
  .reading-input{flex:1 1 100%;}
}

/* ---------- shared wood framing ----------
   The Entrance and the Inn had drifted apart: the Entrance frames panels in
   2px #8c562d with a 12px radius and a dark drop shadow, while the Inn used a
   lighter 2px #9d7d50 with a 14px radius, and its instruction band used a 1px
   border at 9px. Same game, two different woods. These tokens make the Inn
   match the Entrance rather than restyling the Entrance, because the Entrance
   is the approved illustrated look. */
:root{
  --wood-edge:#8c562d;
  --wood-edge-soft:rgba(156,95,48,.8);
  --wood-shadow:rgba(55,30,18,.76);
  --wood-radius:12px;
  --paper:linear-gradient(180deg,#fffaf0,#efe0be);
}

.inn-object,.inn-action,.inn-drop-zone{
  border-color:var(--wood-edge);
  border-radius:var(--wood-radius);
  background:var(--paper);
  box-shadow:0 5px 0 var(--wood-shadow);
}
.inn-instruction,
.inn-stage .inn-instruction{
  border:1px solid rgba(203,145,85,.34);
  border-radius:var(--wood-radius);
  background:rgba(38,22,14,.55);
}
.inn-stage .inn-instruction::before{color:#c9a267;}
.inn-scene-zones{border-radius:var(--wood-radius);}
.inn-clue{border-left-color:var(--wood-edge);}
.question-control{
  border-color:var(--wood-edge);
  border-radius:var(--wood-radius);
  background:var(--paper);
}
.question-control.is-primary{box-shadow:0 3px 0 var(--wood-shadow);}
/* Raised to match the specificity of .inn-replies .reply-option and the
   .inn-stage scoped rules, which kept the old lighter drop shadow. */
.inn-replies .reply-option,
.inn-stage .inn-object,
.inn-stage .inn-action,
.inn-stage .inn-drop-zone{box-shadow:0 5px 0 var(--wood-shadow);}

/* Testing aid, not part of the lesson: dashed so it reads as a tool. */

/* The Inn's dialogue sits in the narrow context column of the split desktop
   layout. Side by side, the fox took about 38% of a 325px column and left the
   speech card 200px, which wrapped a normal N2 sentence to two or three
   characters per line. Below the width where that column stays comfortable,
   stack the character above the speech so the sentence gets the full column. */
/* Scope by the stage, not by the dialogue class: Kon-led stages deliberately
   share .entrance-dialogue for the transparent fox, so excluding that class
   also excluded the Inn, which is the case that needed fixing. The Entrance
   itself has its own full-width dock layout and must keep it. */
@media(max-width:1400px){
  /* The shell computes as grid here, not flex, so flex-direction did nothing
     and the fox kept its own column. Collapse it to a single column instead. */
  #screen-game:not(.entrance-stage) .dialogue{display:block;}
  #screen-game:not(.entrance-stage) .dialogue .speech{width:100%;}
  #screen-game:not(.entrance-stage) .dialogue #avatar-slot{display:block; margin:0 auto 8px;}
}
/* ...but not on a phone, where the stack costs a screenful.
 *
 * The rule above exists for the narrow context COLUMN of the split desktop
 * layout, where a fox beside the speech left the sentence about 200px. A
 * phone has no such column - the layout is a single block, so the dialogue
 * already spans the whole card - and stacked, the portrait and the speech
 * came to 184px of a 851px screen for two things that fit side by side in 88.
 *
 * That mattered because the whole question did not fit: measured on a 393x851
 * phone the page came to about 1009px, so the first answer sat at y=719 and
 * the rest were below the fold. Every question needed a scroll before the
 * learner could see what they were choosing between, which is the one thing
 * this screen exists to show. These rules and the trims below buy that back.
 *
 * Same selector as the rule above, so it wins on source order alone; keep it
 * after that block. */
@media(max-width:760px){
  #screen-game:not(.entrance-stage) .dialogue{
    display:grid; grid-template-columns:64px minmax(0,1fr);
    align-items:center; gap:9px;
  }
  #screen-game:not(.entrance-stage) .dialogue #avatar-slot{margin:0;}
  #screen-game:not(.entrance-stage) .dialogue .speech{width:auto;}
  .inn-stage .avatar.avatar-animated{width:64px; height:64px;}
  /* The two step cues are scaffolding, not content: they say which half of
     the screen to look at. They keep their words and give back their padding. */
  .inn-stage .inn-focus-cue{padding:3px 8px 3px 5px; margin-bottom:4px; font-size:.7rem;}
  /* The HUD wraps to two rows on a phone - the back link and stars, then the
     gauge and the wallet. Both rows stay; the air between them goes. */
  .inn-stage .hud{gap:2px 10px;}
  .inn-stage .learning-context .narration{padding:5px 9px; margin-bottom:5px;}
  .inn-stage .learning-context .dialogue{margin-bottom:8px;}
  /* The place and the question number are a few characters each and were
     taking a row apiece. Sharing one costs nothing - the row still wraps if
     a longer place name needs it - and buys a line back for the answers. */
  .inn-stage .stage-meta .scene-label{width:auto;}
  /* The place is 143px and the question number 57 in a 324px row, but the
     phase chips sit between them in the markup and flex wraps in DOM order,
     so each was taking a row of its own. Reordering pairs the two short ones
     without moving anything in the HTML - and "月見宿・N2 - 問題 5 / 5" is the
     more natural reading anyway. */
  .inn-stage .stage-meta .scene-label{order:1}
  .inn-stage .stage-meta .encounter-status{order:2}
  .inn-stage .stage-meta .stage-phase-row{order:3}
  .inn-stage .stage-meta #inn-journey{order:4}
  .inn-stage #inn-journey{padding-top:2px;}
  .inn-stage .inn-journey-status{margin-bottom:1px;}
}
/* A document is the thing to read here; Kon only gives a one-line direction.
   Keep those two compactly side by side instead of stacking a centred portrait
   over a padded card and pushing the notice downward. This also overrides the
   generic narrow-column stack above, including ordinary browser widths. */
@media(max-width:1400px){
  #screen-game.inn-stage .game-layout:has(.reading-document) .dialogue.entrance-dialogue{
    display:grid;grid-template-columns:64px minmax(0,1fr);align-items:center;gap:8px;padding:7px
  }
  #screen-game.inn-stage .game-layout:has(.reading-document) .dialogue.entrance-dialogue::before{display:none}
  #screen-game.inn-stage .game-layout:has(.reading-document) .dialogue #avatar-slot{
    display:block;width:64px;height:76px;margin:0
  }
  #screen-game.inn-stage .game-layout:has(.reading-document) .dialogue.entrance-dialogue .speech{
    width:auto;min-height:0;padding:8px 32px 8px 10px
  }
}
@media(max-width:760px){
  #screen-game.inn-stage .game-layout:has(.reading-document) .learning-context{padding-top:8px}
}
/* ...except once the speech column is wide again. The stack above exists
   because the fox's column left the card ~200px on a 4-column context; a
   reply or word-choice screen now splits the row evenly, so the card has
   ~400px and the fox can stand beside it as designed - which also stops
   the stack from eating the vertical space that made these screens look
   half-empty. ID-strength selector because the rule it overrides has one. */
@media(min-width:1100px){
  #screen-game.inn-stage .game-layout:has(.inn-replies) .dialogue{display:grid;}
  #screen-game.inn-stage .game-layout:has(.inn-replies) .dialogue .speech{width:auto;}
  #screen-game.inn-stage .game-layout:has(.inn-replies) .dialogue #avatar-slot{margin:0;}
}
/* Japanese has no spaces, so word-break:keep-all - which I added here - stopped
   the line breaking at all and pushed it out past the card edge. Let it wrap
   anywhere, which is normal for Japanese text. */
.jp-line{overflow-wrap:anywhere; word-break:normal;}

/* Testing aid: visible enough to find, distinct enough not to read as lesson UI. */

/* Inside the illustrated room the drop zones were solid cream cards, so the
   artwork was mostly hidden behind pale rectangles. They still need to read as
   targets, so keep the frame and the drop shadow but let the room show through,
   and put the label on its own chip so it stays legible over the art. */
.inn-room-viewport .inn-drop-zone{
  background:rgba(255,250,240,.2);
  border-color:rgba(140,86,45,.9);
  box-shadow:0 3px 0 rgba(55,30,18,.45);
}
.inn-room-viewport .inn-drop-zone:hover,
.inn-room-viewport .inn-drop-zone.is-target{background:rgba(255,250,240,.45);}
.inn-room-viewport .inn-drop-zone .inn-caption{
  padding:1px 6px;
  border-radius:6px;
  background:rgba(46,28,16,.82);
  color:#fff3dc;
}

/* The 「コン (Kon)」 name tab hangs 29px above the speech card. In the Entrance
   that space is empty scene; in the Inn the narration sits directly above, so
   the tab landed on the last line of it. Reserve the tab's height there. */
#screen-game:not(.entrance-stage) .dialogue{margin-top:38px;}

/* Episode opening. The card is plainly visible; only the transform is
   animated. An earlier version faded opacity from 0 and the element stayed at
   0 - the entrance was invisible rather than animated. Never let a decorative
   animation decide whether content can be seen. */
.episode-open{
  display:flex; align-items:center; justify-content:center;
  min-height:260px; padding:24px;
}
.episode-open-card{
  max-width:420px; padding:26px 28px; text-align:center;
  border:2px solid var(--wood-edge); border-radius:var(--wood-radius);
  background:var(--paper); box-shadow:0 6px 0 var(--wood-shadow);
  animation:episode-card-rise .3s cubic-bezier(.22,1,.36,1);
}
@keyframes episode-card-rise{ from{transform:translateY(10px);} to{transform:translateY(0);} }
.episode-open-kicker{margin:0; color:#9a5f30; font-size:.7rem; font-weight:900; letter-spacing:.16em;}
.episode-open-title{margin:6px 0 4px; font-family:'Shippori Mincho',serif; font-size:1.3rem; color:#2d2926;}
.episode-open-note{margin:0 0 16px; color:#6b5844; font-size:.82rem;}

/* Correction card: no room, one prominent clock. The bar is the primary signal
   and the number is the fallback for anyone who cannot judge a shrinking bar. */
.repair-card{gap:14px;}
.repair-timer{
  position:relative; height:26px; overflow:hidden;
  border:2px solid var(--wood-edge); border-radius:var(--wood-radius);
  background:rgba(46,28,16,.14);
}
.repair-timer-fill{
  position:absolute; inset:0 auto 0 0; width:100%;
  background:linear-gradient(90deg,#e8963c,#f7c877);
  transition:width .1s linear;
}
.repair-timer b{
  position:relative; display:block; line-height:26px; text-align:center;
  color:#2d2926; font-size:.78rem; font-weight:800;
}
@media(prefers-reduced-motion:reduce){ .repair-timer-fill{transition:none;} }

/* Episode briefing: the rules of the hour, stated before the first guest. */
.episode-brief{max-width:480px; text-align:left;}
.episode-brief .episode-open-kicker{text-align:center;}
.episode-brief-list{margin:12px 0 18px; padding-left:20px; color:#3f3125; font-size:.86rem; line-height:1.7;}
.episode-brief-list li{margin-bottom:4px;}
.episode-brief .btn{display:block; margin:0 auto;}

/* The job board: tonight's five jobs, and which are already done.
   Deliberately a checklist rather than a score card - the same board is shown
   before each day, and jobs tick off on it, so it reads as the shift going
   well rather than as three progress reports interrupting a story. */
.job-board{max-width:480px; text-align:left;}
/* The board is not a question, so the hint control has nothing to offer on it.
   Hidden from here rather than from the renderer because the finished day left
   an inline display on that button, and !important is what reliably beats it
   regardless of which write happens to land last. */
.answer-workspace:has(.job-board) #hint-btn,
.answer-workspace:has(.job-board) #hint-box,
.answer-workspace:has(.teach-card) #hint-btn,
.answer-workspace:has(.teach-card) #hint-box{display:none!important;}
.job-board .episode-open-kicker,
.job-board .episode-open-title,
.job-board .episode-open-note{text-align:center;}
.job-board .btn{display:block; margin:0 auto;}
.job-board-list{margin:14px 0 18px; padding:0; list-style:none;}
/* Three columns, and the word stacked over its sense in the middle one. Four
   flat columns fitted the card's own max-width but not the answer column it
   actually sits in, where every row wrapped. */
.job-row{
  display:grid; grid-template-columns:1.5em 1fr auto;
  align-items:center; gap:10px;
  padding:6px 2px; border-bottom:1px solid rgba(93,66,42,.16);
}
.job-row:last-child{border-bottom:0;}
.job-mark{color:#a08a6a; font-size:.78rem; font-weight:900; text-align:center;}
.job-text{display:flex; flex-direction:column; gap:1px; min-width:0;}
.job-word{font-family:'Shippori Mincho',serif; font-size:1rem; line-height:1.5; color:#2d2926;}
.job-word rt{font-size:max(8px,.48em); color:#7a6752;}
.job-gloss{color:#6b5844; font-size:.74rem; line-height:1.3;}
/* What this part of the stage is for, under the list it applies to. */
.job-goal{
  margin:0 0 14px; padding:9px 11px;
  border-radius:8px; background:rgba(154,95,48,.08);
  color:#5c4a38; font-size:.76rem; line-height:1.6;
}
.job-state{color:#9a8b74; font-size:.68rem; font-weight:800; letter-spacing:.04em; white-space:nowrap;}
/* Done is stated in colour and in words, not colour alone. */
.job-row.done .job-mark,
.job-row.done .job-state{color:var(--moss);}
.job-row.done .job-word{color:#3f5a34;}

/* The correction list: the words still owed, from every place.
   Built on the job board's rows, because it is the same kind of thing - a
   list of work with a state per line - and a second row style would be a
   second thing to learn for no gain. */
/* The list owns the screen, the way a teaching card does.
   This is a list to read and act on, not a conversation: Kon's one sentence
   about it rides in the card, and her panel - which on a phone overlapped the
   card's own heading - is gone. Keyed on the card rather than on .inn-stage,
   because the list is reached from the map and belongs to no one place. */
.game-layout:has(.fix-card){grid-template-columns:1fr;}
.game-layout:has(.fix-card) .learning-context{display:none;}
.answer-workspace:has(.fix-card){grid-column:1/-1;}
.fix-card{max-width:520px; margin-inline:auto;}
.fix-lead{margin:0 0 14px; color:#6b5844; font-size:.86rem; line-height:1.55;}
.fix-list{margin:14px 0 16px; padding:0; list-style:none; max-height:46vh; overflow-y:auto;}
.fix-row{
  display:grid; grid-template-columns:1fr auto auto;
  align-items:center; gap:10px;
  padding:8px 2px; border-bottom:1px solid rgba(93,66,42,.16);
}
.fix-row:last-child{border-bottom:0;}
.fix-text{display:flex; flex-direction:column; gap:1px; min-width:0;}
.fix-word{font-family:'Shippori Mincho',serif; font-size:1.05rem; line-height:1.5; color:#2d2926;}
.fix-word rt{font-size:max(8px,.48em); color:#7a6752;}
.fix-gloss{color:#6b5844; font-size:.74rem; line-height:1.3;}
/* Where the word was missed. Quiet: it is context for the learner deciding
   what to work on, not part of the question. */
.fix-place{color:#9a8b74; font-size:.68rem; font-weight:800; white-space:nowrap;}
/* Striking a word off is the learner's call, so it is a real button with a
   real target, not an icon. Quiet enough not to compete with practising,
   which is the action that actually teaches. */
.fix-drop{
  min-height:44px; padding:6px 12px;
  border:1px solid rgba(154,95,48,.4); border-radius:999px;
  background:transparent; color:#8a5a2b;
  font:800 .7rem 'Zen Maru Gothic',sans-serif; cursor:pointer; white-space:nowrap;
}
.fix-drop:hover,.fix-drop:focus-visible{background:rgba(154,95,48,.12);}
.fix-card .btn{display:block; width:100%; margin:0 auto;}
.fix-card .btn-ghost{margin-top:8px; font-size:.8rem; opacity:.85;}
@media(max-width:420px){
  /* The place name drops below the word rather than squeezing the row: three
     columns at this width left nothing for the button to sit in. */
  .fix-row{grid-template-columns:1fr auto;}
  .fix-place{grid-column:1; grid-row:2; margin-top:2px;}
  .fix-drop{grid-column:2; grid-row:1/3;}
}

/* Kon's once-a-day word about the list, on the map. */
.map-fix-nudge{
  white-space:normal;
  margin:8px 0 0; padding:8px 12px;
  border-left:3px solid var(--lantern-bright); border-radius:0 8px 8px 0;
  background:rgba(230,178,96,.16);
  color:#f0dcb6; font-size:.76rem; line-height:1.5;
}

/* A word being taught is read, not scanned, so it is set at a size that
   rewards looking at it - the boards already do the list-row version.
   Cream like the board it follows, not one of the dark cards: the two are
   consecutive screens and a palette flip between them reads as a different
   part of the game rather than the next beat of the same one. */
.teach-card{text-align:center;}
.answer-workspace:has(.teach-card) .inn-focus-cue{display:none!important;}
@media(max-width:760px){
  body:has(#screen-game[style*="display: block"] .teach-card) .feedback-open{visibility:hidden;pointer-events:none;}
  body:has(#home-shelf button) .feedback-open{visibility:hidden;pointer-events:none;}
}
.teach-count{margin:0 0 10px; color:#9a8b74; font-size:.7rem; font-weight:900; letter-spacing:.14em;}
.teach-lead{margin:0 0 14px; color:#6b5844; font-size:.9rem; line-height:1.5;}
.teach-word{margin:0 0 6px; font-family:'Shippori Mincho',serif; font-size:2.2rem; line-height:1.4; color:#2d2926;}
.teach-word rt{font-size:max(8px,.32em); color:#7a6752;}
.teach-sense{margin:0 0 14px; color:#6b5844; font-size:.86rem; line-height:1.4;}
/* The pattern is the part that makes an N2 word usable, so it gets the chip
   rather than a line of body text that the eye slides past. */
.teach-pattern{
  display:inline-block; margin:0 0 16px; padding:5px 14px;
  border:1px solid rgba(154,95,48,.4); border-radius:999px;
  background:rgba(154,95,48,.12);
  color:#8a5a2b; font-size:.92rem; font-weight:800;
}
.teach-sentence{margin:0 0 18px; font-size:1.1rem; line-height:1.95; color:#3f3125;}
/* The word is highlighted where it stands rather than repeated underneath,
   so what is learned is the word doing its job in a sentence. */
.teach-focus{color:#9a5f30; font-weight:700; border-bottom:2px solid rgba(154,95,48,.45);}
.teach-card .btn{display:block; margin:0 auto;}
/* The check that follows the card. Cream like the card, and stacked rather
   than in a row: three N2 words side by side on a phone wrap to two lines
   each and stop reading as three separate choices. */
.teach-question{margin:0 0 14px; font-size:1rem; color:#3f3125;}
.teach-check{display:flex; flex-direction:column; gap:8px; align-items:stretch;}
/* The word being asked about, smaller than on the teaching card: there it is
   the subject, here it is the question. */
.teach-word-asked{margin:0 0 10px; font-size:1.7rem;}
/* English options, so the body font rather than the Japanese serif, and left
   aligned - a gloss like "adjustment, coordination" is a phrase to read, and
   centred phrases of different lengths have no common edge to scan down. */
.teach-card .teach-option{display:block; width:100%; min-height:48px; margin:0; font-size:.95rem; line-height:1.4; padding:11px 16px; text-align:left;}
.teach-check.is-answered .teach-option{pointer-events:none;}
.teach-check.is-answered .teach-option:disabled{opacity:1;}
.teach-check.is-answered .teach-option:disabled:not(.is-picked):not(.is-right){color:#3e3428;}
.teach-answer-slot{scroll-margin-bottom:16px;}
.teach-answer{margin:16px 0 12px; font-size:1rem; color:#8a5a2b;}
/* The five words, listed once more as the studying ends. Rows rather than a
   sentence: it is a list being checked off, not prose. */
.teach-recap{
  margin:14px 0 16px; padding:0; list-style:none;
  display:flex; flex-wrap:wrap; justify-content:center; gap:6px 8px;
}
.teach-recap-word{
  padding:5px 12px; border:1px solid rgba(154,95,48,.35); border-radius:999px;
  background:rgba(154,95,48,.1);
  font-family:'Shippori Mincho',serif; font-size:1rem; color:#3f3125;
}
/* A right answer is marked and moves on, so the mark is the whole reply. It
   rides in the chosen button, at the end of the line the learner just read. */
.teach-mark{float:right; margin-left:10px; font-size:1.1rem; font-weight:900; color:var(--moss);}
.teach-mark-wrong{color:#a8372c;}
/* Both halves of the answer are on the options, and neither is carried by
   colour alone - the ✓ and the ✗ say it, the fill and the border repeat it,
   and the line beneath still says it in words.

   The wrong option used to fade to opacity .75, which made the one thing the
   learner most needs to look at the faintest thing on the card. It is at full
   strength now; it is the two options nobody touched that recede. */
.teach-option.is-picked{box-shadow:none; transform:translateY(2px);}
.teach-option.is-right{border-color:var(--moss); background:rgba(126,161,132,.2); color:#2f4a28; font-weight:800;}
.teach-option.is-wrong{border-color:#a8372c; background:rgba(168,55,44,.12); color:#8d3226; opacity:1;}
.teach-check.is-answered .teach-option:disabled:not(.is-picked):not(.is-right){opacity:.55;}

/* A question being asked again because it was missed says so, plainly and
   before the request. The same task twice with nothing marking it is the
   thing that reads as a bug. */
.retry-flag{
  display:flex; flex-wrap:wrap; align-items:center; gap:8px;
  margin:0 0 9px; padding:7px 11px;
  border-left:3px solid var(--lantern-bright); border-radius:0 8px 8px 0;
  background:rgba(230,178,96,.16);
  color:#f0dcb6; font-size:.74rem; line-height:1.5;
}
.retry-flag-tag{
  padding:2px 9px; border-radius:999px;
  background:var(--lantern-bright); color:#3a2412;
  font-size:.68rem; font-weight:900; letter-spacing:.04em;
}

/* What kind of part this is, in three words, under the day it belongs to.
   The day names - 基礎, 実践, 挑戦 - say where you are in the shift but not
   what you are being asked to do, which was reported as not knowing whether a
   part was teaching, drilling or testing. */
.day-kind{
  display:inline-block; margin:0 auto 12px; padding:4px 12px;
  border:1px solid rgba(154,95,48,.4); border-radius:999px;
  background:rgba(154,95,48,.12);
  color:#8a5a2b; font-size:.72rem; font-weight:800; letter-spacing:.03em;
}
.job-board .day-kind,
.miss-review .day-kind,
.episode-brief .day-kind{display:block; width:max-content; margin-left:auto; margin-right:auto;}
/* The dark cards only. The job board and the mistake list are cream, and
   giving them the light-on-dark chip made the label almost invisible on the
   very screen it exists to explain. */
#install-panel .day-kind,
#save-panel .day-kind{border-color:rgba(230,178,96,.42); background:rgba(230,178,96,.14); color:#e8c98f;}

/* The build a tester is looking at. Quiet, but readable - it is the first
   thing to ask for when someone reports something already fixed. */
.app-version{
  margin:10px 0 0; color:rgba(241,205,139,.55);
  font-size:.66rem; letter-spacing:.06em; text-align:center;
}

/* Offered, not forced: a reload in the middle of a question is its own bug.
   Fixed to the bottom because an update can land on any screen. */
/* The update notice. It reuses .about-panel and .about-card, so it is the
   same dialog as About and Save data - one shape for "the game is asking you
   something", rather than a third thing to learn. What is added here is
   emphasis: this one has a gold edge, because unlike the others it was not
   opened on purpose and has to earn a glance. */
.update-card{
  max-width:400px; text-align:center;
  border:2px solid var(--lantern-bright);
  box-shadow:0 18px 48px rgba(10,5,2,.6), 0 0 0 1px rgba(255,212,137,.18);
}
.update-kicker{
  margin:0 0 4px; color:var(--lantern-bright);
  font-size:.68rem; font-weight:900; letter-spacing:.18em; text-transform:uppercase;
}
.update-card h2{color:#ffe4a0;}
/* Update first, and at a size a thumb finds without aiming. Later is a way
   out, not an equal choice, so it is quieter and underneath. */
.update-card .btn{display:block; width:100%; margin:14px auto 0; min-height:46px;}
.update-card .btn-ghost{margin-top:8px; min-height:40px; font-size:.8rem; opacity:.8;}

/* Tester safety controls are fixed because a save failure can happen on any
   screen. The update notice no longer needs room made for it here - it is a
   dialog, and the rule below hides this button while any dialog is open. */
.storage-warning{
  position:fixed; top:max(10px,env(safe-area-inset-top,0px)); left:50%; z-index:120;
  width:min(560px,calc(100% - 28px)); margin:0; padding:10px 14px;
  transform:translateX(-50%); border:1px solid #ffd27a; border-radius:12px;
  background:#4a2718; box-shadow:0 8px 22px rgba(0,0,0,.38);
  color:#fff0cf; font-size:.82rem; font-weight:800; line-height:1.4; text-align:center;
}
.feedback-open{
  position:fixed; right:max(14px,env(safe-area-inset-right,0px)); bottom:max(14px,env(safe-area-inset-bottom,0px)); z-index:110;
  min-height:44px; padding:10px 16px; border:1px solid rgba(255,218,156,.8); border-radius:999px;
  background:#2b1c11; box-shadow:0 6px 18px rgba(0,0,0,.34);
  color:#fff0cf; font:800 .8rem 'Zen Maru Gothic',sans-serif; cursor:pointer;
}
.feedback-open:hover,.feedback-open:focus-visible{background:#4a2d19;outline:3px solid var(--lantern-bright);outline-offset:2px}
/* Feedback is a utility, not the current task. On a phone a floating pill
   sat over answers, notices, the ★ blank and the dinner-time Later button
   whichever way it was lifted, because the page scrolls underneath it. So on
   a phone it is not floating at all: it sits in the page flow below the game. */
@media(max-width:760px){
  .feedback-open{position:static;display:block;margin:14px auto 0;}
  /* When the Entrance ends, Kon's line and 「路地を見る」 are pinned to the
     bottom of the screen and covered this button even scrolled to the end.
     The only step left is that button; Feedback is back on the map. */
  body:has(.entrance-stage.entrance-complete) .feedback-open{visibility:hidden;pointer-events:none}
}
/* A modal owns the screen and already offers a close or response action. */
body:has(.about-panel:not([hidden])) .feedback-open{visibility:hidden;pointer-events:none}

/* Install and save controls on the title screen. Quiet by design - they sit
   under the way in, not beside it. */
.title-utility{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-top:10px;}
.title-menu-wrap{position:relative;}
.title-menu{
  position:absolute;left:0;bottom:calc(100% + 8px);z-index:8;
  display:grid;min-width:190px;padding:7px;border:1px solid rgba(247,215,159,.48);
  border-radius:12px;background:rgba(17,12,14,.96);box-shadow:0 12px 28px rgba(0,0,0,.45);
}
.title-menu[hidden]{display:none}
.title-menu-action{
  min-height:44px;padding:8px 10px;border:0;border-radius:8px;background:transparent;
  color:#fff0cf;text-align:left;font:700 .8rem 'Zen Maru Gothic',sans-serif;cursor:pointer;
}
.title-menu-action:hover,.title-menu-action:focus-visible{background:rgba(247,200,119,.16);outline:2px solid var(--lantern-bright);outline-offset:1px}
.title-menu-danger{color:#ffd4c5}
.title-menu .app-version{margin:5px 4px 1px;padding-top:6px;border-top:1px solid rgba(247,215,159,.2);text-align:left;}
.install-steps{
  margin:14px 0 18px; padding-left:22px;
  color:#e6d2b2; font-size:.82rem; line-height:1.75; text-align:left;
}
.install-steps::marker{color:#e6d2b2;}
.install-steps li{margin-bottom:6px;}
.install-warn{
  margin:12px 0 0; padding:10px 12px;
  border-left:3px solid var(--momiji); border-radius:0 8px 8px 0;
  background:rgba(198,93,63,.16);
  color:#f0d8bc; font-size:.78rem; line-height:1.6; text-align:left;
}
#install-panel .about-card{max-width:440px;}
#install-panel .btn-primary{display:block; margin:0 auto 4px;}
.save-actions{display:flex; flex-wrap:wrap; gap:10px; justify-content:center; margin:14px 0 8px;}
.save-status{min-height:1.4em; margin:0 0 14px; color:#e6d2b2; font-size:.78rem; text-align:center;}
#save-panel .about-card{max-width:460px;}

/* The day's mistakes, with what the words mean. Only the missed ones: a list
   of all five with four already known is a list you skim. */
.miss-review{max-width:480px; text-align:left;}
.miss-review .episode-open-kicker,
.miss-review .episode-open-title,
.miss-review .episode-open-note{text-align:center;}
.miss-review .btn{display:block; margin:0 auto;}
.miss-review-list{margin:14px 0 18px; padding:0; list-style:none;}
.miss-row{
  display:flex; flex-direction:column; gap:2px;
  padding:9px 10px; margin-bottom:8px;
  border-left:3px solid var(--momiji);
  background:rgba(154,95,48,.07); border-radius:0 8px 8px 0;
}
.miss-row:last-child{margin-bottom:0;}
.miss-word{font-family:'Shippori Mincho',serif; font-size:1.08rem; line-height:1.5; color:#2d2926;}
.miss-word rt{font-size:max(8px,.46em); color:#7a6752;}
.miss-sense{color:#4a4038; font-size:.82rem;}
.miss-note{color:#8a745c; font-size:.72rem;}
.answer-workspace:has(.miss-review) #hint-btn,
.answer-workspace:has(.miss-review) #hint-box{display:none!important;}

/* The correction clock is the strictest thing in the game, so it reads as a
   countdown rather than decoration, and turns urgent in the last two seconds. */
.repair-timer.is-countdown{height:30px;}
.repair-timer.is-countdown b{line-height:30px; font-size:.82rem; letter-spacing:.02em;}
.repair-timer-fill.is-urgent{background:linear-gradient(90deg,#c2543a,#e8963c);}

/* A notice is laid out as a notice: its line breaks carry meaning, and reading
   room by room is the task. Without pre-line the whole board collapses into one
   paragraph and the retrieval becomes a wall of text. */
.jp-line{white-space:pre-line;}

/* A notice or schedule is a document, not dialogue. It gets the wide answer
   panel, one fact per line, generous leading, and a tabular figure so the
   times line up. 190 characters inside a 325px speech bubble is unreadable
   however clearly it is written. */
.reading-document{
  margin:0 0 14px;
  padding:16px 18px 14px;
  border:2px solid var(--wood-edge);
  border-radius:var(--wood-radius);
  background:var(--paper);
  color:#2d2926;
  box-shadow:0 4px 0 var(--wood-shadow);
  font-family:'Shippori Mincho',serif;
  font-variant-numeric:tabular-nums;
}
.reading-document-heading{
  margin:0 0 10px;
  padding-bottom:8px;
  border-bottom:1px dashed rgba(140,86,45,.55);
  font-size:1.02rem; font-weight:800; letter-spacing:.02em;
}
.reading-document-body{
  margin:0; padding:0; list-style:none;
  font-size:1rem; line-height:2;
}
.reading-document-body li{padding:1px 0;}
.reading-document-body li.is-rule{
  margin-top:6px; padding-left:1em; text-indent:-1em;
  color:#6b4a2c; font-size:.94rem; line-height:1.8;
}
.reading-document-ask{
  margin:12px 0 0; padding-top:10px;
  border-top:1px solid rgba(140,86,45,.35);
  font-weight:800; font-size:1.02rem;
}
@media(max-width:760px){
  .reading-document{padding:13px 14px;}
  .reading-document-body{font-size:.95rem; line-height:1.65;}
  .reading-document-body li.is-rule{margin-top:4px;font-size:.9rem;line-height:1.55}
  .reading-document-heading{margin-bottom:7px;padding-bottom:6px}
  .reading-document-ask{margin-top:9px;padding-top:8px}
}

/* Practice sits under the location's own action, as a quieter second option. */
.map-detail-practice{margin-top:8px; font-size:.8rem;}

.practice-score{
  margin:.6em 0 0;
  font-size:2.1em;
  font-weight:700;
  text-align:center;
  color:var(--paper);
}

/* An answered question keeps its choices on screen while the explanation is
   read, so they have to stop reading as choices. */
.question-control.is-settled{
  opacity:.55;
  cursor:default;
}
.question-control.is-settled.is-picked{
  opacity:1;
  border-color:var(--wood-edge);
  box-shadow:0 0 0 2px var(--wood-edge) inset;
}
.question-control.is-settled.is-correct{
  opacity:1;
  border-color:var(--moss);
  box-shadow:0 0 0 2px var(--moss) inset;
}

  /* Being paid. The chip starts visible and is removed on a timer, so a
     learner with reduced motion still sees it - it just does not travel. */
  .money-hud{position:relative}
  .payout-chip{
    /* Clear of the pill's own digits at every frame, including the
       reduced-motion resting position (the keyframes are killed by the
       global *{animation:none!important} rule, so this base `top` is what
       those learners actually see for the chip's whole 1.1s lifetime). It
       used to sit at -0.35em and rise through translateY(.3em) at 0%, which
       put the "+Y" text right over the "Y" balance as it passed. */
    position:absolute; left:50%; top:-2em;
    transform:translate(-50%,0);
    font-weight:800; font-size:.95em; color:#ffe4a0;
    text-shadow:0 1px 3px rgba(20,10,4,.85);
    pointer-events:none; white-space:nowrap; z-index:5;
    animation:payout-rise 1s ease-out forwards;
  }
  @keyframes payout-rise{
    0%{opacity:0; transform:translate(-50%,.3em) scale(.9)}
    18%{opacity:1; transform:translate(-50%,-.1em) scale(1.06)}
    100%{opacity:0; transform:translate(-50%,-1.9em) scale(1)}
  }
  .money-hud.is-paid{
    border-color:rgba(255,228,160,.95);
    box-shadow:0 0 0 2px rgba(255,216,128,.35), 0 0 14px rgba(255,200,110,.45);
    transition:box-shadow .18s ease-out, border-color .18s ease-out;
  }

  /* A glossed word: readable as part of the sentence, tappable as a word. */
  .gloss{
    display:inline; position:relative;
    font:inherit; color:inherit; background:none;
    border:0; border-bottom:1px dotted currentColor;
    padding:0; margin:0; cursor:help;
    line-height:inherit; letter-spacing:inherit;
    /* A glossed word is one word: a line wrap inside it printed 出発 as
       「ご出」 at a line end and 「発」 on the next. */
    white-space:nowrap;
  }
  .gloss-ruby{white-space:nowrap}
  .gloss:hover,.gloss:focus-visible{background:rgba(255,214,140,.28); border-radius:3px}
  .gloss.is-open{background:rgba(255,214,140,.4); border-radius:3px}
  .gloss-bubble{
    position:absolute; left:50%; bottom:100%; transform:translateX(-50%);
    margin-bottom:6px; z-index:40;
    display:block; min-width:max-content; max-width:16em; white-space:normal;
    padding:6px 10px; border-radius:9px;
    background:rgba(28,16,10,.96); border:1px solid rgba(247,200,119,.55);
    box-shadow:0 6px 18px rgba(0,0,0,.4);
    font-size:.82rem; line-height:1.45; text-align:left; white-space:normal;
    cursor:default;
  }
  .gloss-reading{display:block; color:#ffe4a0; font-weight:700}
  .gloss-meaning{display:block; color:#f3e6d4}
  .gloss-ruby{ruby-position:over;color:inherit;text-decoration:underline dotted rgba(255,211,138,.68);text-underline-offset:3px}
  .gloss-ruby rt{color:#c88949;font-size:max(8px,.54em);font-weight:800;letter-spacing:0;text-decoration:none}
  .challenge-transcript{display:grid;gap:3px;margin:8px 0 0;padding:7px 9px;border-left:3px solid #ba8144;background:rgba(255,250,238,.56);font-size:.82rem;line-height:1.55}
  .challenge-transcript b{color:#80512c;font-size:.72rem;letter-spacing:.08em}
  @media(max-width:560px){ .gloss-bubble{max-width:12em} }

  /* わが家 - the room, and the one screen with nothing to answer. */
  .home-room{display:flex; flex-direction:column; align-items:center; gap:10px}
  .home-room-art{width:100%; max-width:650px; height:auto; border-radius:12px;
    border:1px solid var(--wood-edge); box-shadow:0 8px 24px rgba(20,10,4,.45)}
  /* These three lines sit directly on the game panel, which is a cream
     gradient - not the dark alley background the rest of the home styling was
     written against. Pale-on-pale measured 1.02:1, which is invisible rather
     than merely low contrast. Dark ink on cream, and a deep amber for the
     numbers instead of pale gold. */
  /* Light ink again, and this time genuinely on a dark surface rather than on
     a cream one that was assumed to be dark. */
  .home-room-note{margin:10px 0 0; color:#f3e6d4; font-size:.95rem}
  .home-room-note b{color:#ffd489}
  /* The stage takes the room's own light, so nothing around the picture reads
     as a different surface. */
  #screen-game.home-stage{
    max-width:1000px; overflow:hidden; color:#f7ecd8;
    background:linear-gradient(180deg,#2f2116 0%,#1b130c 62%,#150f09 100%);
    box-shadow:0 28px 70px rgba(3,7,20,.55),0 0 0 1px rgba(247,200,119,.18);
  }
  .home-stage .stage-bar{display:none}
  .home-stage .hud{border-color:rgba(247,215,159,.28)}
  .home-stage .breadcrumb,.home-stage .scene-label,.home-stage .narration{color:#fff0cf}
  .home-stage .narration{display:none}
  .home-stage .hud-stars{color:#f3be6d}
  /* The default layout is two columns - the dialogue on the left, the answer on
     the right - because normally there is a question to answer beside what Kon
     is saying. At home there is no question, so the room takes the full width
     and Kon speaks above it, the way the entrance does. */
  .home-stage .game-layout{grid-template-columns:minmax(0,1fr); grid-template-areas:"bar" "context" "answer"; gap:10px 0}
  .home-stage .learning-context,.home-stage .answer-workspace{grid-column:1}
  .home-stage .answer-workspace,.home-stage #scene{padding:0}
  /* And it runs past the panel's own inset, so the artwork meets the frame
     rather than sitting on a margin of it. */
  .home-stage .home-scene-camera{margin-left:-14px; margin-right:-14px; width:calc(100% + 28px)}
  .home-stage .home-room{gap:0}
  .home-stage .home-room > :not(.home-scene-camera){padding-left:14px; padding-right:14px}

  .home-scene-camera{position:relative;width:100%;overflow:hidden;background:#1b130c}
  .home-scene-viewport{width:100%;overflow:hidden}
  .home-pan-hint{display:none}

  .home-scene-chrome{
    position:absolute;left:12px;right:12px;top:10px;z-index:200;
    display:grid;grid-template-columns:1fr auto auto;align-items:center;gap:12px;
    min-height:38px;padding:5px 7px 5px 10px;border-radius:10px;
    color:#fff0cf;background:rgba(35,20,12,.58);
    border:1px solid rgba(255,224,170,.24);
    box-shadow:0 6px 18px rgba(7,4,2,.2),inset 0 1px rgba(255,244,214,.12);
    backdrop-filter:blur(12px) saturate(125%);
  }
  /* 32px minimum, like every other piece of chrome. These came in at 22px tall,
     which is the same miss the breadcrumb had: the label is small on purpose,
     the thing you press should not be. */
  /* The scene now carries its own painted way out - the yard's path and the
   * room's veranda - so this corner link was a second control for the same
   * action, in a different language, a few hundred pixels away. The painted
   * one is the larger target and sits where the fiction puts the exit, so
   * this one stands down. Revert by deleting the display:none rule below. */
  .home-scene-chrome .home-scene-back{display:none}
  .home-scene-back{justify-self:start;padding:6px 8px;border:0;background:transparent;color:inherit;
    cursor:pointer;font-weight:700;font-size:.78rem;min-height:32px}
  .home-shop-chrome button{min-height:32px;padding:6px 10px}
  .home-scene-money{padding:5px 10px;border-radius:999px;background:rgba(18,10,6,.46);
    color:#ffe1a2;font-weight:800;font-size:.82rem}
  .home-scene-back:focus-visible{outline:2px solid #ffd489;outline-offset:2px}

  .home-scene-controls{
    position:relative;z-index:6;width:calc(100% - 24px);margin:0 auto;
    padding:7px 12px 8px!important;border-radius:10px;
    background:rgba(35,31,36,.80);
    border:1px solid rgba(255,224,170,.24);
    box-shadow:0 8px 22px rgba(5,3,2,.25),inset 0 1px rgba(255,244,214,.12);
    backdrop-filter:blur(12px) saturate(125%);
  }
  .home-first-reward{margin:0 0 8px;padding:10px 11px;border:1px solid rgba(255,210,122,.62);border-radius:8px;background:linear-gradient(130deg,rgba(124,68,24,.74),rgba(47,27,16,.88));box-shadow:inset 0 1px rgba(255,244,214,.13);color:#f9e7bf;text-align:center}
  .home-first-reward p{margin:0;font-size:.8rem;line-height:1.35}
  .home-first-reward-kicker{margin-bottom:3px!important;color:#ffd27a!important;font-size:.62rem!important;font-weight:900;letter-spacing:.12em;text-transform:uppercase}
  .home-first-reward .btn{margin-top:8px;padding:9px 15px;font-size:.82rem}
  @media (min-width:700px) and (max-height:850px){
    .home-stage .home-scene-controls{width:calc(min(100%, calc((100vh - 290px) * 16 / 9)) - 24px)}
  }
  @media(max-width:620px){
    .home-scene-chrome{left:7px;right:7px;top:7px;min-height:34px;gap:6px;padding:3px 5px 3px 7px}
    .home-scene-back{font-size:.68rem;padding:6px 4px}
    .home-scene-money{font-size:.72rem;padding:4px 7px}
    .home-scene-controls{
      width:100%;margin:0 auto;padding:8px 8px 9px!important;border-radius:0 0 10px 10px;
      background:linear-gradient(180deg,rgba(25,14,8,.92),rgba(25,14,8,.98));
      border-top:0;backdrop-filter:none;
    }
  }
  @media(prefers-reduced-transparency:reduce){
    .home-scene-chrome,.home-scene-controls{background:#25160d;backdrop-filter:none}
  }
  @media(prefers-contrast:more){
    .home-scene-chrome,.home-scene-controls{background:#160d08;border-color:#ffe1a2}
  }

  #screen-game.home-stage .stage-phase-row{display:none!important}
  /* Nothing is asked at home, so when Kon has nothing to say the speech panel
     is an empty box with a mute button in it, taking a hundred pixels off the
     top of the yard for no reason. */
  #screen-game.home-stage #dialogue-shell.is-silent{display:none}
  /* Nothing at home is a question, so the furigana switch has no sentence to
     act on and the understanding gauge has no material to measure - a 理解度 0%
     bar at your own house is both meaningless and discouraging. The wallet
     stays: it is the one number the house is about. */
  #screen-game.home-stage .romaji-toggle,
  #screen-game.home-stage .mastery-hud{display:none}

  /* The attribution screen. Reachable from the title, dismissible three ways. */
  .title-about-link{
    display:block; margin:10px auto 0; padding:4px 8px;
    background:none; border:0; cursor:pointer;
    color:#e8d9c0; opacity:.75; font-size:.82rem; text-decoration:underline;
  }
  .title-about-link:hover,.title-about-link:focus-visible{opacity:1}
  .about-panel{
    position:fixed; inset:0; z-index:130; display:flex;
    align-items:center; justify-content:center; padding:16px;
    background:rgba(12,7,3,.72);
  }
  .about-panel[hidden]{display:none}
  .about-card{
    max-width:520px; max-height:86vh; overflow-y:auto;
    padding:20px 22px; border-radius:var(--wood-radius);
    border:1px solid var(--wood-edge); background:#2b1c11; color:#f3e6d4;
    box-shadow:0 18px 48px rgba(10,5,2,.6);
  }
  .about-card h2{margin:0 0 6px; font-size:1.15rem}
  .about-card h3{margin:16px 0 6px; font-size:.95rem; color:#ffe4a0}
  .about-card p,.about-card li{font-size:.86rem; line-height:1.65; margin:6px 0}
  .about-card ul{margin:6px 0; padding-left:1.1em}
  .about-lead{opacity:.85}
  .about-caveat{opacity:.9; border-left:3px solid var(--wood-edge); padding-left:10px}
  .about-card a{color:#ffd489}
  .about-card .btn{min-height:44px;margin-top:16px}
  .about-card .btn-ghost{color:#fff0cf;border-color:rgba(255,218,156,.46);}
  .about-card .btn-ghost:hover{background:rgba(255,218,156,.13);}
  .reset-confirm-card{max-width:420px;}
  .reset-confirm-actions{margin:16px 0 0;}
  .reset-confirm-actions .btn{margin-top:0;}
  .feedback-card{width:min(440px,100%);}
  .feedback-choices{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:16px 0;}
  .feedback-card .feedback-choice{min-height:44px;margin:0;padding:10px 8px;color:#fff0cf;border-color:rgba(255,218,156,.46);}
  .feedback-card .feedback-choice:hover,.feedback-card .feedback-choice:focus-visible{background:rgba(255,218,156,.13);}
  .feedback-status{min-height:1.5em;color:#ffe4a0;font-size:.82rem;text-align:center;}
  @media(max-width:390px){.feedback-choices{grid-template-columns:1fr;}.feedback-card{padding:18px 16px;}}

  /* Review mode: a working bar, deliberately plain. */
  .review-bar{
    position:fixed; top:0; left:0; right:0; z-index:80;
    display:flex; gap:8px; align-items:center; flex-wrap:wrap;
    padding:8px 10px; background:#161009; border-bottom:1px solid var(--wood-edge);
    font-size:.8rem; color:#f3e6d4;
  }
  .review-bar[hidden]{display:none}
  .review-bar select{max-width:300px; flex:0 1 auto}
  .review-bar input{flex:1 1 240px; min-width:180px; padding:5px 8px;
    border-radius:6px; border:1px solid var(--wood-edge); background:#241a10; color:#f3e6d4}
  .review-bar button{padding:5px 10px; border-radius:6px; cursor:pointer;
    border:1px solid var(--wood-edge); background:#3a2819; color:#f3e6d4}
  .review-count{opacity:.8; white-space:nowrap}
  body.reviewing{padding-top:52px}
  .review-export-box{width:min(680px,92vw); height:60vh; padding:12px;
    border-radius:8px; border:1px solid var(--wood-edge);
    background:#1b130c; color:#f3e6d4; font-size:.8rem; line-height:1.5}

  .review-flag{display:flex; align-items:center; gap:5px; white-space:nowrap; cursor:pointer}
  .review-flag input{width:16px; height:16px; cursor:pointer}
  .review-bar.is-flagged{background:#3a1410; border-bottom-color:#a2503f}

  /* The room at わが家, and the shop that fills it.
     Cards are large because this is a thumb interface, and the room itself is
     the only place in the game with no clock running. */
  .home-goal{margin:0 0 2px; text-align:center; font-size:.82rem; color:#f4dfba}
  .home-goal b{color:#ffd489}
  .home-hint{color:#ffd489; font-weight:700}
  .home-tabs{display:flex; gap:8px; justify-content:center; margin:7px 0 0}
  .home-pet-manage-panel{display:flex;flex-direction:column;gap:6px;margin:7px auto 0;max-width:320px;width:100%}
  .home-pet-manage-row{display:flex;align-items:center;gap:8px;justify-content:center;flex-wrap:wrap}
  .home-pet-manage-name{color:#f3e6d4;font-size:.85rem;min-width:3em;text-align:right}
  .home-pet-manage-count{min-width:3em;text-align:center;color:#ffd489;font-size:.85rem}
  .pet-count-btn{padding:4px 10px;border-radius:7px;cursor:pointer;border:1px solid rgba(255,224,170,.38);
    background:rgba(24,14,8,.48);color:#fff0cf;font-size:.82rem}
  .pet-count-btn:hover:not(:disabled),.pet-count-btn:focus-visible{border-color:#ffd489;background:rgba(121,80,43,.86);outline:none}
  .pet-count-btn:disabled{opacity:.35;cursor:default}
  .home-main-menu{display:flex;justify-content:center;gap:8px;margin-top:7px;flex-wrap:wrap}
  .home-menu-button{min-width:92px;min-height:39px;padding:7px 16px;border-radius:9px;cursor:pointer;
    border:1px solid rgba(255,224,170,.38);background:rgba(24,14,8,.48);color:#fff0cf;font-weight:700}
  .home-menu-button:hover,.home-menu-button:focus-visible,.home-menu-button.is-on{
    border-color:#ffd489;background:rgba(121,80,43,.86);outline:none}
  .home-yard-more{position:relative}
  .home-yard-more summary{display:grid;place-items:center;width:38px;height:34px;border-radius:9px;cursor:pointer;
    list-style:none;border:1px solid rgba(255,224,170,.38);background:rgba(24,14,8,.48);color:#fff0cf;font-weight:800}
  .home-yard-more summary::-webkit-details-marker{display:none}
  .home-yard-more > div{position:absolute;right:0;bottom:calc(100% + 7px);z-index:12;display:grid;gap:5px;
    width:max-content;padding:7px;border-radius:9px;background:rgba(25,18,22,.96);border:1px solid rgba(255,224,170,.32);
    box-shadow:0 10px 28px rgba(0,0,0,.42)}
  .home-yard-more button{padding:7px 10px;border-radius:7px;cursor:pointer;text-align:left;
    border:0;background:transparent;color:#f2dfbd}
  .home-yard-more button:hover,.home-yard-more button:focus-visible{background:rgba(255,224,170,.12);outline:none}
  .home-tab{padding:6px 18px; border-radius:999px; cursor:pointer; font-size:.9rem; white-space:nowrap; flex-shrink:0;
    border:1px solid var(--wood-edge); background:#2b1f14; color:#e8d3ae}
  .home-tab.is-on{background:#f3c568; color:#2b1f14; border-color:#f3c568}
  /* width:100% matters more than it looks. The room is a column flex box with
     align-items:center, so without it the dock sizes to its own max-content -
     five 96px tracks - and at 320px eight of the fourteen cards sat off the
     side of the screen with no way to reach them. */
  .home-shelf{display:grid; gap:8px; justify-content:center; width:100%;
    grid-template-columns:repeat(auto-fill, minmax(96px, 1fr)); max-width:520px; margin:0 auto}
  .home-card{display:flex; flex-direction:column; align-items:center; gap:2px;
    padding:8px 4px 6px; border-radius:10px; cursor:pointer;
    border:1px solid var(--wood-edge); background:#2b1f14; color:#f3e6d4}
  .home-card-art{width:100%; height:52px}
  .home-card-name{font-size:.85rem}
  .home-card-sub{font-size:.72rem; opacity:.75}
  .home-card.is-picked{border-color:#ffd489; box-shadow:0 0 0 2px rgba(255,212,137,.45)}
  .home-card.is-locked{opacity:.45}
  .home-card.is-owned{opacity:.55; cursor:default}

  /* On a phone the storage shelf is a tray, not a grid.
   *
   * As a grid it was 340px tall for nine things and grew a row for every few
   * more, while the room above it is 453 and the controls between them 139:
   * 1270px of page inside an 851px screen. So picking something meant
   * scrolling down past the room, and placing it meant scrolling back up -
   * once per object, and worse the more you owned, which is exactly backwards
   * for the part of the game that rewards owning more.
   *
   * One row that scrolls sideways instead. Its height no longer depends on
   * how much you have, and sticking it to the bottom of the screen keeps the
   * room and the things you are putting in it visible together, so a whole
   * decorating session needs no vertical scrolling at all.
   *
   * justify-content has to be unset here, not merely left alone. The grid
   * above centres itself, which cost nothing while it was capped at 520px and
   * wrapped - it never overflowed, so there was nothing to push off the edge.
   * This row overflows by design, and centring an overflowing row splits that
   * overflow across both ends. A scroll container has no room before its start
   * edge, so the left half is not off screen, it is unreachable: the tray sits
   * at scrollLeft 0 with its first card already cut down the middle, and cut
   * deeper with every object bought. Twice on purpose - an engine that does
   * not know `safe` drops that line and keeps flex-start, which is never
   * wrong, it only forgoes centring a row short enough to fit. */
  @media(max-width:760px){
    .home-stage .home-shelf{
      position:sticky; bottom:0; z-index:60;
      display:flex; grid-template-columns:none; max-width:none;
      justify-content:flex-start; justify-content:safe center;
      gap:8px; padding:8px 10px calc(8px + env(safe-area-inset-bottom,0px));
      overflow-x:auto; overflow-y:hidden;
      scroll-snap-type:x proximity; overscroll-behavior-x:contain;
      background:linear-gradient(180deg,rgba(24,14,8,.88),rgba(24,14,8,.98));
      border-top:1px solid rgba(224,164,79,.28);
      scrollbar-width:none;
    }
    .home-stage .home-shelf::-webkit-scrollbar{display:none}
    .home-stage .home-shelf .home-card{
      flex:0 0 auto; width:84px; scroll-snap-align:start;
      padding:6px 4px 5px;
    }
    .home-stage .home-shelf .home-card-art{height:40px}
    .home-stage .home-shelf .home-card-name{font-size:.76rem; white-space:nowrap}
    .home-stage .home-shelf .home-card-sub{font-size:.66rem}
  }
  /* Explicit, not inherited: the panel's ink is dark and this sits on the dark
     stage, so inheriting made it invisible the moment the home went dark. */
  .home-empty{grid-column:1/-1; text-align:center; font-size:.85rem; color:#cbb894}

  .home-shop-stage{position:relative;min-height:620px;overflow:hidden;background:#17100a;color:#f7ecd8}
  .home-shop-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;filter:brightness(.62) saturate(.88)}
  .home-shop-stage::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(13,8,5,.72),rgba(13,8,5,.28) 52%,rgba(13,8,5,.62));pointer-events:none}
  .home-shop-chrome{position:absolute;left:14px;right:14px;top:12px;z-index:3;display:grid;
    grid-template-columns:1fr auto 1fr;align-items:center;min-height:44px;padding:5px 10px;border-radius:10px;
    background:rgba(38,22,13,.72);border:1px solid rgba(255,224,170,.28);backdrop-filter:blur(12px)}
  .home-shop-chrome button{justify-self:start;border:0;background:transparent;color:#fff0cf;cursor:pointer;font-weight:700}
  .home-shop-chrome strong{font-family:'Shippori Mincho',serif;font-size:1.05rem;color:#ffe1a2}
  .home-shop-chrome span{justify-self:end;padding:5px 10px;border-radius:999px;background:rgba(15,8,5,.62);color:#ffe1a2;font-weight:800}
  .home-shop-panel{position:relative;z-index:2;width:min(760px,calc(100% - 48px));margin:82px auto 24px;
    padding:20px;border-radius:14px;background:rgba(39,23,14,.88);border:1px solid rgba(255,224,170,.28);
    box-shadow:0 18px 50px rgba(0,0,0,.48);backdrop-filter:blur(16px)}
  .home-shop-kicker{margin:0;text-align:center;color:#d7b77c;font-size:.7rem;letter-spacing:.12em}
  .home-shop-panel h2{margin:2px 0 12px;text-align:center;font-family:'Shippori Mincho',serif;color:#fff0cf}
  .home-shop-categories{display:flex;justify-content:center;gap:8px;margin-bottom:14px}
  .home-shop-notice{min-height:1.25em;margin:0 0 10px;text-align:center;color:#ffe1a2;font-weight:700}
  .home-shop-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:10px}
  .home-shop-grid .home-card{min-height:112px;background:rgba(29,17,10,.86)}
  .home-pet-shop-sprite{width:64px;height:64px;margin:0 auto;background-size:400% 100%;background-position:0 0;background-repeat:no-repeat;image-rendering:pixelated}
  .home-card.is-active-pet{opacity:1;border-color:#ffd489;box-shadow:0 0 0 2px rgba(255,212,137,.45);cursor:default}
  .home-card.is-active-pet .home-card-sub{color:#ffd489}
  @media(max-width:620px){
    .home-shop-stage{min-height:620px}
    .home-shop-panel{width:calc(100% - 20px);margin-top:68px;padding:12px}
    .home-shop-chrome{left:7px;right:7px;top:7px}
    .home-shop-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
    .home-shop-categories{overflow-x:auto;justify-content:flex-start;padding-bottom:2px}
    .home-shop-categories .home-tab{padding:6px 12px}
  }

  /* A placed item is liftable; an empty corner only shows while something is
     waiting to go into it, so the room is never covered in markers. */
  .home-item{cursor:pointer}
  .home-item:hover{filter:brightness(1.15)}
  .home-target{cursor:pointer}
  .home-target-ring{fill:rgba(255,212,137,.16); stroke:#ffd489; stroke-width:2;
    stroke-dasharray:6 5}
  .home-target-mark{fill:#ffd489; font-size:28px; font-weight:700}
  @media (prefers-reduced-motion:no-preference){
    .home-target-ring{animation:home-pulse 1.6s ease-in-out infinite}
  }
  @keyframes home-pulse{50%{fill:rgba(255,212,137,.34)}}

  /* The yard and the room.
     Both are a painted background with things positioned on top by percentage,
     so the scene stays intact from 320px to a desktop window. The aspect ratio
     is fixed to the artwork's, because a slot placed at 62% of the height only
     means anything if the height follows the picture. */
  /* Full bleed, no frame.
     The entrance works because the artwork is the panel rather than a picture
     placed on it, and the interface floats on top in its own wooden boxes. The
     home was doing the opposite: a bordered rectangle centred on a sheet of
     cream, with the stage visible above and below it. Same treatment now.

     The 16/9 box stays, because every slot in the yard is a percentage of it
     and a cropped background would move all eight. */
  .home-scene{
    position:relative; width:100%; margin:0;
    aspect-ratio:16/9; overflow:hidden; background:#1b130c;
    container-type:inline-size;
  }
  @media (min-width:700px) and (max-height:850px){
    .home-stage .home-scene-camera{
      width:min(100%, calc((100vh - 290px) * 16 / 9));
      margin-left:auto;
      margin-right:auto;
    }
  }
  /* The bottom edge fades into the panel instead of stopping on a line, so the
     dock underneath reads as part of the same room. */
  .home-scene::after{
    content:""; position:absolute; left:0; right:0; bottom:0; height:14%;
    pointer-events:none;
    background:linear-gradient(180deg, rgba(27,19,12,0) 0%, rgba(27,19,12,.92) 100%);
  }
  .home-scene-bg{position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block}
  .home-scene::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;transition:background .45s ease}
  .home-scene.light-morning .home-scene-bg{filter:none}
  .home-scene.light-morning::before{background:transparent}
  .home-scene.light-day .home-scene-bg{filter:none}
  .home-scene.light-day::before{background:transparent}
  .home-scene.light-evening .home-scene-bg{filter:none}
  .home-scene.light-evening::before{background:transparent}
  .home-scene.light-night .home-scene-bg{filter:none}
  .home-scene.light-night::before{background:transparent}
  .home-scene.light-morning::after,.home-scene.light-day::after{background:transparent}
  .home-scene.light-evening::after{background:linear-gradient(180deg,rgba(27,19,12,0) 0%,rgba(27,19,12,.34) 100%)}
  .home-scene.light-night::after{background:linear-gradient(180deg,rgba(27,19,12,0) 0%,rgba(27,19,12,.62) 100%)}
  /* The yard at night is dark because the sun has set. The room is not: it has
     a lamp burning in it, which is why its painting measures warm rather than
     moonlit. Both were being darkened by the same rules, so a lit room read as
     an unlit one. These two lift only the interior, and must stay below the
     `filter:none` pair above, which they match on specificity and beat on
     order. 53.7 x 1.6 puts the room on 85.9, level with the furniture and the
     cat; the floor gradient comes down with it, or it would crush the tatami
     the furniture is standing on back into the dark. */
  .home-interior-scene.light-night .home-scene-bg{filter:brightness(1.6) saturate(1.04)}
  .home-interior-scene.light-night::after{
    background:linear-gradient(180deg,rgba(27,19,12,0) 0%,rgba(27,19,12,.38) 100%)}
  @media (prefers-reduced-motion:reduce){.home-scene::before{transition:none}}

  /* Mobile home camera: keep the painting and every percentage-based object
     intact, but give it enough height to read and let a thumb pan across it. */
  @media(max-width:620px){
    /* The house, unlike the map, is safe to grow: the scene's width is
       derived from its height and every object sits at a percentage of the
       scene, so it scales as one picture and nothing drifts. That makes the
       artwork itself the thing that takes the leftover height on a tall
       phone - a bigger house to look at rather than a bigger empty box.
       Capped so the 飾る and 店 buttons underneath stay on screen without
       scrolling. Each height is declared twice: the dvh line is the real
       one, the vh line is what an engine without dvh keeps. */
    .home-scene-viewport{
      height:clamp(300px,50vh,480px);overflow-x:auto;overflow-y:hidden;
      touch-action:pan-x;overscroll-behavior-x:contain;scrollbar-width:none;
    }
    .home-scene-viewport{height:clamp(300px,50dvh,480px)}
    .home-scene-viewport::-webkit-scrollbar{display:none}
    .home-scene-viewport .home-scene{
      width:calc(clamp(300px,50vh,480px) * 16 / 9);height:100%;max-width:none;
      aspect-ratio:16/9;
    }
    .home-scene-viewport .home-scene{width:calc(clamp(300px,50dvh,480px) * 16 / 9)}
    .home-pan-hint{
      display:block;margin:0;padding:5px 10px;pointer-events:none;text-align:center;
      white-space:nowrap;color:#fff0cf;background:#25160d;
      border-top:1px solid rgba(255,224,170,.24);font-size:.68rem;font-weight:800;
    }
    .home-scene-chrome .home-scene-back{display:block}
  }

  /* Items sit on their slot's centre point, so the anchor is the middle of the
     footprint rather than a corner that drifts as the picture scales. */
  /* A plant carries its own vertical anchor inline, because each growth stage
     sits at a different height inside its picture. */
  /* Width comes from the slot now, because it varies with depth in the yard.
     The shadow is what stops a cut-out looking pasted on: the painting lights
     everything from the house, so anything standing in it needs to sit in that
     light rather than float above it. */
  .home-plant, .home-item{position:absolute; width:20%; cursor:pointer; line-height:0}
  /* Room furniture, not stock. Anchored at its foot like a floor object, so
     the percentage in home-room.js means the same thing for both, and graded
     with the room the way the owned items are - an ungraded cut-out standing
     against a painted wall is the thing that reads as pasted on. */
  .home-fixture{
    position:absolute; height:auto; transform:translate(-50%,-100%);
    pointer-events:none; user-select:none; opacity:.97;
    filter:drop-shadow(0 3px 5px rgba(25,13,6,.5)) saturate(.86) sepia(.10) brightness(.94) contrast(.97);
  }
  /* Width is set inline from the cat's own depth, so the flat 13% here is only
     the fallback for a render before the pet module has spoken. It used to be
     the actual size everywhere, which made the cat a giant against the back
     wall while every object around it shrank with the perspective. */
  .home-pet{
    position:absolute; left:0; top:0; z-index:3; width:7.5%; aspect-ratio:1;
    pointer-events:none; line-height:0;
    filter:drop-shadow(0 3px 4px rgba(28,16,8,.48)) saturate(.9) sepia(.08);
  }
  /* Bird sprite feet sit at 90.6% of their square cell. Matching that baseline
     to a painted roof, fence, sill or floor keeps every idle pose supported. */
  /* The cat is lit by the hour too.
   *
   * It carried one fixed filter for every time of day, so at midday it was
   * darker than the floor and at night it stayed bright on a dim one - the
   * same mismatch the furniture had, and the same reason it read as sitting on
   * the picture rather than in it. These track the item rules above. */
  /* The cat is graded per scene as well as per hour.
   *
   * It is the one object that appears in both, and the two no longer share a
   * brightness: at midday the room's tatami is 1.35x its evening painting while
   * the yard's ground is 1.99x. One value cannot sit in both, so the yard rules
   * follow the plants and the room rules follow the furniture. */
  /* The calico is a white-bibbed cat, and white clips almost at once.
   *
   * Measured across the production sheets, the brightest 5% of the fur reaches
   * 255 at between 1.05x and 1.16x - the grooming sheet is tightest at 1.05.
   * The yard was asking 1.55 and the room 1.30, so in daylight the cat was not
   * lit, it was blown to flat white with its markings gone. That is the whole
   * of "the cat looks unnatural in both scenes".
   *
   * Daylight is therefore carried by contrast rather than by brightness. A
   * contrast below 1 pulls the picture toward mid-grey, which lifts the dark
   * fur far more than it moves the white, so the cat reads brighter while its
   * highlights stay under 255. Brightness never exceeds 1.10.
   *
   * At night in the yard it takes the doorway lamp like everything else -
   * `--pet-lamp`, set by the renderer and updated as the cat walks. Indoors
   * that variable is 1: the room has its own lighting and no falloff. */
  .home-interior-scene.light-morning .home-pet{
    filter:drop-shadow(0 3px 4px rgba(28,16,8,.42)) saturate(.92) sepia(.06) brightness(1.05) contrast(.92) hue-rotate(-6deg)}
  .home-interior-scene.light-day .home-pet{
    filter:drop-shadow(0 3px 4px rgba(28,16,8,.38)) saturate(.90) sepia(.04) brightness(1.06) contrast(.87)}
  .home-interior-scene.light-evening .home-pet{
    filter:drop-shadow(0 3px 4px rgba(28,16,8,.46)) saturate(1.00) sepia(.04) brightness(1.00) contrast(.97)}
  .home-interior-scene.light-night .home-pet{
    filter:drop-shadow(0 3px 5px rgba(8,10,18,.64)) saturate(.76) sepia(.05) brightness(.72) contrast(1.10) hue-rotate(6deg)}

  .home-yard-scene.light-morning .home-pet{
    filter:drop-shadow(0 3px 4px rgba(28,16,8,.40)) saturate(.93) sepia(.05) brightness(1.09) contrast(.87) hue-rotate(-5deg)}
  .home-yard-scene.light-day .home-pet{
    filter:drop-shadow(0 3px 4px rgba(28,16,8,.36)) saturate(.92) sepia(.03) brightness(1.10) contrast(.86)}
  .home-yard-scene.light-evening .home-pet{
    filter:drop-shadow(0 3px 4px rgba(28,16,8,.46)) saturate(1.00) sepia(.04)
      brightness(calc(0.96 + 0.10 * var(--pet-lamp, 0.4))) contrast(.97)}
  .home-yard-scene.light-night .home-pet{
    filter:drop-shadow(0 3px 5px rgba(8,10,18,.62))
      brightness(calc(0.62 + 0.32 * var(--pet-lamp, 0.4)))
      contrast(calc(1.16 - 0.08 * var(--pet-lamp, 0.4)))
      saturate(calc(0.72 + 0.28 * var(--pet-lamp, 0.4)))
      sepia(calc(0.18 * var(--pet-lamp, 0.4)))
      hue-rotate(calc(16deg - 23deg * var(--pet-lamp, 0.4)))}

  .home-pet > span{
    display:block; width:100%; height:100%; background-repeat:no-repeat;
    transform:scaleX(var(--pet-facing,1)); transform-origin:center bottom;
  }
  .home-pet[data-pet-behavior="curl-sleep"] > span,
  .home-pet[data-pet-behavior="side-sleep"] > span,
  .home-pet[data-pet-behavior="loaf"] > span,
  .home-pet.is-bird[data-pet-behavior="perch"] > span,
  .home-pet.is-bird[data-pet-behavior="sleep"] > span{
    animation:pet-breathe 2.8s ease-in-out infinite;
  }
  @keyframes pet-breathe{
    0%,100%{transform:scaleX(var(--pet-facing,1)) scaleY(.992)}
    50%{transform:scaleX(var(--pet-facing,1)) scaleY(1.008)}
  }
  @media (prefers-reduced-motion:reduce){.home-pet > span{animation:none}}
  /* Reduced motion changes whether it moves, not how big it is. */
  /* Three small things, all of which stop a cut-out reading as pasted on.

     The shadow gives it contact with the ground. The warm grade pulls a
     neutrally-lit picture towards the scene's dusk - the yard is lit from the
     house at sunset, and anything dropped into it lit flatly from the front
     announces itself. And the plants sit under the same soft light overlay the
     lanterns cast, rather than in front of it. */
  .home-plant img, .home-plant svg{
    filter:saturate(.92) sepia(.10) brightness(.97);
  }
  .home-item img, .home-item svg{filter:drop-shadow(0 2px 4px rgba(28,16,8,.45))}
  .home-item{width:18%}
  .home-item[data-slot-item="screen-left"],
  .home-item[data-slot-item="screen-right"]{transform-origin:50% 100%}
  /* svg as well as img: a drawn stand-in that is not sized here falls back to
     the browser's default replaced-element size and renders several times the
     height of the whole yard. */
  .home-plant img, .home-plant svg,
  .home-item img, .home-item svg{width:100%; height:auto; display:block}
  .home-plant:hover, .home-item:hover{filter:brightness(1.12)}

  /* The room painting is warm and low-contrast. Raw reward cut-outs were
     brighter and sharper than everything behind them, so they read as stickers.
     Grade them with the scene and give floor objects a soft contact shadow. */
  .home-item img, .home-item svg{
    position:relative;z-index:1;opacity:.97;
    filter:drop-shadow(0 2px 3px rgba(25,13,6,.48)) saturate(.84) sepia(.10) brightness(.92) contrast(.96);
  }
  /* Each object is lit like the room it stands in.
   *
   * The scene gets two things the objects were not getting. First the
   * background's own filter, which at midday is brightness(1.22) while the
   * objects were on 1.02 - a fifth darker than the floor they sit on, which is
   * what makes a correctly placed object still read as pasted on. Morning was
   * out by a tenth, night by a little, and evening had no rule at all, so the
   * objects went ungraded from late afternoon onwards.
   *
   * Second, `.home-scene::before` washes the whole picture with the hour's
   * colour, and it sits at z-index 1 while objects sit at 65 to 108 - so the
   * wash paints under them and never reaches them. Rather than restack the
   * scene, each object's own filter carries an equivalent of that wash: a
   * touch more brightness where the wash is pale, and a real drop at night
   * where it is a 24% blue.
   *
   * The numbers track the background rules a few lines above. Change one and
   * change its partner, or the objects start floating again. */
  /* Plants are graded by the hour too, and against the yard rather than the room.
   *
   * They had no per-hour rule at all. That was survivable while one evening
   * painting was filtered for every hour, because the filter moved the plants
   * and their ground together. Now that each hour is its own painting the
   * plants are the only thing in the yard that does not change: measured at
   * ground level, the yard runs 1.78x the evening painting in the morning,
   * 1.99x at midday and 0.61x at night, so an ungraded plant was half as
   * bright as the gravel it stood in at noon and nearly twice as bright at
   * night.
   *
   * The numbers are deliberately short of those ratios. `brightness` multiplies
   * and clips at white, so applying a full 1.99 would blow the pale blossoms
   * out to paper; these sit near the ratio raised to three quarters, which
   * closes most of the gap while keeping the highlights. The room's own values
   * a few lines below are measured the same way against the tatami. */
  .light-morning .home-plant img,.light-morning .home-plant svg{
    filter:saturate(.68) sepia(.07)
      brightness(min(1.04, var(--plant-lift-max,1.6))) contrast(.89) hue-rotate(-5deg)}
  /* The lift the ground asks for, capped at what the picture can take.
     See PLANT_LIFT_CEILING in app.js: the sakura's blossoms clip at 1.07 and
     the camellia's leaves not until 1.77, so one number cannot serve both. */
  .light-day .home-plant img,.light-day .home-plant svg{
    filter:saturate(.75) sepia(.04)
      brightness(min(1.07, var(--plant-lift-max,1.6))) contrast(.90)}
  /* After the sun goes, the house lamp is the only light in the yard, so a
     plant's distance from the doorway starts to matter. `--plant-lamp` is 1 at
     the door and 0 at the far corners - see plantLampProximity in app.js.
     At dusk the sky still does most of the work, so the lamp only tips it. */
  .light-evening .home-plant img,.light-evening .home-plant svg{
    filter:saturate(.76)
      brightness(calc(0.92 + 0.10 * var(--plant-lamp, 0.3))) contrast(.94)
      sepia(calc(0.07 + 0.05 * var(--plant-lamp, 0.3)))}
  /* 夜桜 - cherry blossom seen at night, which is a lit subject and not a dim
     one. The first attempt at this made distance mean darkness and ran the
     range 0.48 to 0.92, so the front trees - the largest and most prominent in
     the frame - came out the darkest in the yard. That is backwards. What the
     thing actually looks like is blossom glowing pale against a blue-black
     sky, lit from underneath by lanterns while the trunks stay dark.

     So depth is carried by colour temperature rather than by brightness:

     `contrast` above 1 is what separates blossom from bark. Cherry blossom is
     the brightest thing in the picture and the trunk among the darkest, so
     pushing them apart imitates uplighting without needing to mask anything.

     `brightness` stays high and moves only a little, 0.80 to 0.96. Enough to
     read as depth, not enough to put a tree out.

     `hue-rotate` does the real work. Far from the lamp it swings blue, toward
     the sky; near it, back to amber. That reads as distance far better than
     dimming does, and it is what the eye actually sees at a night hanami.

     The warm drop-shadow is a glow rather than a shadow - a few pixels of
     lantern-pink haze around the canopy, which is the halo blossom has under
     lights and the reason photographs of it look lit from within. */
  .light-night .home-plant img,.light-night .home-plant svg{
    filter:drop-shadow(0 0 calc(10px + 14px * var(--plant-lamp, 0.3)) rgba(255,188,206,calc(0.16 + 0.26 * var(--plant-lamp, 0.3))))
      brightness(calc(0.68 + 0.34 * var(--plant-lamp, 0.3)))
      contrast(calc(1.22 - 0.10 * var(--plant-lamp, 0.3)))
      saturate(calc(0.74 + 0.30 * var(--plant-lamp, 0.3)))
      sepia(calc(0.22 * var(--plant-lamp, 0.3)))
      hue-rotate(calc(20deg - 27deg * var(--plant-lamp, 0.3)))}

  .light-morning .home-fixture,.light-morning .home-item img,.light-morning .home-item svg{
    filter:saturate(.82) sepia(.08) brightness(1.00) contrast(.93) hue-rotate(-7deg)}
  .light-day .home-fixture,.light-day .home-item img,.light-day .home-item svg{
    filter:saturate(.84) sepia(.05) brightness(.98) contrast(.94)}
  .light-evening .home-fixture,.light-evening .home-item img,.light-evening .home-item svg{
    filter:saturate(.90) sepia(.05) brightness(.98) contrast(.96)}
  /* Indoors after dark the light is the lamp, not the sun, and a lamp does not
     burn lower at eleven than at seven. These were tuned as if the room went
     dark the way the yard does, and the measured result was a room at a third
     of its daytime brightness with the furniture dimmed to match it.
     Measuring the art: the decor photographs average 101.5 luminance, the cat
     sprites 120.5, and the night room 53.7 against the evening room's 112.5.
     At the old .56 the furniture landed on 56.8 - correctly seated, but seated
     in a room that was too dark - while the cat at .72 landed on 86.7 and was
     the one thing lit for a room with a lamp in it. So the cat was right and
     everything around it was wrong: .85 puts the furniture on 86.3, the
     background lift below puts the room on 85.9, and the cat stays where it
     was. The shadow warms from blue-black to the same brown the other three
     periods use, because the night room measures warm (R-B +53), and the cold
     hue-rotate that fought it is gone. */
  .light-night .home-fixture,.light-night .home-item img,.light-night .home-item svg{
    filter:saturate(.82) sepia(.06) brightness(.85) contrast(.95)}
  /* A plant is seated on the ground the same way furniture is.
   *
   * Furniture had a contact shadow from the start and plants never did, so a
   * tree stood on the gravel with nothing under it and the soil disc baked
   * into its picture read as a sticker laid on top rather than as roots in the
   * ground.
   *
   * It is narrow, because what touches the ground is the trunk and its root
   * flare, not the canopy - a shadow as wide as the blossom would look like a
   * puddle. And it sits at the plant's own ground line rather than at the foot
   * of the box: `--plant-base` is the same figure the renderer uses to stand
   * the plant on its slot, which differs by species and by growth stage. */
  .home-plant::before{
    content:"";position:absolute;z-index:0;left:50%;
    width:calc(var(--contact-width,36) * 1%);
    height:calc(var(--contact-height,6) * 1%);
    bottom:calc(100% - (var(--plant-base,95) * 1%));
    transform:translate(-50%,50%);
    border-radius:50%;
    background:radial-gradient(ellipse,rgba(22,14,8,var(--contact-alpha,.34)),rgba(22,14,8,0) 72%);
    filter:blur(var(--contact-blur,2px));pointer-events:none;
  }
  .home-plant img, .home-plant svg{position:relative;z-index:1}

  /* The base is feathered into the ground rather than tinted over it.
   *
   * The v2 cutouts stand on their own patch of gravel, which is the right fix
   * for the old brown soil disc - but a patch of gravel laid on a yard of
   * gravel still ends somewhere, and that ending is a visible oval seam.
   *
   * An earlier attempt hazed a colour over the rim. That suited a brown disc
   * on grey ground, where the problem was the colour; it is wrong here, where
   * both are gravel and the problem is only the edge. So this fades the edge
   * out instead: two mask layers, added together, keeping everything above the
   * base intact and replacing the patch below it with a soft ellipse that
   * dissolves at its rim. What is left blends because it is the same material
   * as what it lands on.
   *
   * The ellipse is a touch wider than the patch it covers so the seam falls
   * inside the fade rather than on its boundary. */
  .home-plant img{
    -webkit-mask-image:
      linear-gradient(to bottom, #000 0 calc((var(--plant-base,95) - 7) * 1%), transparent calc((var(--plant-base,95) - 7) * 1%)),
      radial-gradient(ellipse 34% 7% at 50% calc((var(--plant-base,95) - 3) * 1%), #000 46%, transparent 100%);
    -webkit-mask-composite: source-over;
    mask-image:
      linear-gradient(to bottom, #000 0 calc((var(--plant-base,95) - 7) * 1%), transparent calc((var(--plant-base,95) - 7) * 1%)),
      radial-gradient(ellipse 34% 7% at 50% calc((var(--plant-base,95) - 3) * 1%), #000 46%, transparent 100%);
    mask-composite: add;
  }

  .home-item.has-contact::before{
    content:"";position:absolute;z-index:0;left:50%;
    width:calc(var(--contact-width,60) * 1%);
    height:calc(var(--contact-height,6) * 1%);
    bottom:calc(100% - (var(--contact-y,100) * 1%));
    transform:translate(-50%,50%);border-radius:50%;
    background:radial-gradient(ellipse,rgba(24,13,7,var(--contact-alpha,.34)),rgba(24,13,7,0) 72%);
    filter:blur(var(--contact-blur,2px));pointer-events:none;
  }

  .home-scene.light-morning{--contact-alpha:.25;--contact-blur:2px}
  .home-scene.light-day{--contact-alpha:.21;--contact-blur:1.5px}
  .home-scene.light-evening{--contact-alpha:.34;--contact-blur:2px}
  .home-scene.light-night{--contact-alpha:.46;--contact-blur:2.5px}

  /* An empty place shows itself only while something is waiting to go into it,
     so the scene is never covered in markers. */
  .home-target{
    position:absolute; z-index:210; transform:translate(-50%,-50%);
    width:44px; height:44px; border-radius:50%; cursor:pointer;
    display:flex; align-items:center; justify-content:center;
    font-size:1.4rem; font-weight:700; color:#ffd489;
    background:rgba(255,212,137,.18); border:2px dashed #ffd489;
  }
  .home-target.is-occupied{border-style:solid; background:rgba(255,212,137,.28)}
  /* A shelf is pressed as a whole rather than at eight points on it, so its
     target takes the shelf's own shape: a rounded rectangle over the
     furniture, sized inline from the spread of the positions it stands for.
     Its own size wins over the 44px circle above, hence the override - and it
     is never smaller than that circle, because it covers a whole shelf. */
  .home-target.is-surface{
    border-radius:10px; min-width:44px; min-height:44px;
    background:rgba(255,212,137,.13); align-items:flex-end; padding-bottom:2px;
  }
  @media (prefers-reduced-motion:no-preference){
    .home-target{animation:home-pulse 1.6s ease-in-out infinite}
  }
  @keyframes home-pulse{50%{background:rgba(255,212,137,.34)}}

  .home-house-hotspot{
    position:absolute; z-index:205; cursor:pointer; border-radius:8px;
    background:transparent; border:2px solid transparent; padding:0;
    display:flex; align-items:flex-end; justify-content:center;
  }
  .home-house-hotspot span{
    font-size:.8rem; color:#f3e6d4; background:rgba(27,19,12,.72);
    border-radius:6px; padding:3px 10px; margin-bottom:6px;
  }
  .home-house-hotspot:hover{border-color:#ffd489}
  .home-house-hotspot:focus-visible{border-color:#ffd489; outline:none}

  .home-leave-house{
    position:absolute; left:12px; top:12px; z-index:205;
    padding:6px 14px; border-radius:999px; cursor:pointer; font-size:.85rem;
    border:1px solid var(--wood-edge); background:rgba(27,19,12,.82); color:#f3e6d4;
  }

  /* A plant that changed stage while the learner was away is the reason to
     come back, so the change is shown rather than simply being there. */
  @media (prefers-reduced-motion:no-preference){
    .home-plant.is-growing{animation:home-grow 900ms ease-out}
  }
  /* Scaling from the foot, so a growing plant rises out of its bed instead of
     swelling around its own middle. The inline anchor stays untouched. */
  .home-plant.is-growing{transform-origin:50% 100%}
  @keyframes home-grow{
    0%{opacity:.35; scale:.72}
    60%{scale:1.06}
    100%{opacity:1; scale:1}
  }

  .home-card-art{display:block; width:100%; height:52px; line-height:0}
  .home-card-art img, .home-card-art svg{width:100%; height:100%; object-fit:contain}
  .home-garden-list{
    grid-column:1/-1; margin:6px 0 0; padding-left:1.1em;
    font-size:.8rem; color:#dcc9a6; text-align:left;
  }

  /* Kon's first visit. The Japanese and the mechanical instruction are kept
     visually apart, because a learner reading both at once is guessing at two
     things instead of doing one. */
  .home-tutorial{
    max-width:820px; margin:0 auto; padding:12px 14px; border-radius:0 0 10px 10px;
    border:1px solid #f3c568; background:rgba(43,31,20,.92); text-align:left;
  }
  .home-tutorial-jp{margin:0 0 6px; font-size:.95rem; line-height:1.6; color:#f7ecd8}
  .home-tutorial-how{margin:0; font-size:.8rem; color:#e3c48c}
  .home-tutorial .btn{margin-top:10px}
  .home-tutorial .btn-ghost{color:#fff0cf;border-color:rgba(255,218,156,.46);}
  .home-tutorial .btn-ghost:hover{background:rgba(255,218,156,.13);}
  .home-card.is-gift{border-color:#ffd489; box-shadow:0 0 0 2px rgba(255,212,137,.4)}
  .home-card.is-gift .home-card-sub{color:#ffd489}
  .home-howto{
    display:block; margin:12px auto 0; padding:6px 14px; border-radius:999px;
    font-size:.78rem; cursor:pointer; min-height:32px;
    border:1px solid var(--wood-edge); background:#2b1f14; color:#e8d3ae;
  }
  .home-howto:hover{background:#3a2819}

  /* Trace paper panels, not a rectangle over the upper room. The mask uses
     the painting's aspect ratio and cover sizing, just like .home-scene-bg,
     so it remains aligned when the mobile camera scales and pans the room. */
  .home-wallpaper{
    position:absolute; inset:0;
    pointer-events:none; mix-blend-mode:multiply; opacity:.55;
    /* Overridden per design - see .blend-normal below. */
    -webkit-mask-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221200%22%20height%3D%22669%22%20viewBox%3D%220%200%201200%20669%22%3E%20%3Cdefs%3E%20%3Cmask%20id%3D%22paper-handles%22%20maskUnits%3D%22userSpaceOnUse%22%20x%3D%220%22%20y%3D%220%22%20width%3D%221200%22%20height%3D%22669%22%20style%3D%22mask-type%3Aluminance%22%3E%20%3Crect%20width%3D%221200%22%20height%3D%22669%22%20fill%3D%22white%22%2F%3E%20%3Cg%20fill%3D%22black%22%3E%20%3Cellipse%20cx%3D%2299%22%20cy%3D%22333%22%20rx%3D%228%22%20ry%3D%2214%22%2F%3E%20%3Cellipse%20cx%3D%22325%22%20cy%3D%22343%22%20rx%3D%223%22%20ry%3D%228%22%2F%3E%20%3Cellipse%20cx%3D%22458%22%20cy%3D%22344%22%20rx%3D%227%22%20ry%3D%228%22%2F%3E%20%3Cellipse%20cx%3D%22741%22%20cy%3D%22344%22%20rx%3D%227%22%20ry%3D%228%22%2F%3E%20%3Cellipse%20cx%3D%22912%22%20cy%3D%22343%22%20rx%3D%223%22%20ry%3D%2210%22%2F%3E%20%3Cellipse%20cx%3D%221101%22%20cy%3D%22335%22%20rx%3D%228%22%20ry%3D%2214%22%2F%3E%20%3C%2Fg%3E%20%3C%2Fmask%3E%20%3C%2Fdefs%3E%20%3Cg%20fill%3D%22white%22%20mask%3D%22url(%23paper-handles)%22%3E%20%3Cpolygon%20points%3D%220%2C0%20115%2C65%20114%2C547%200%2C587%22%2F%3E%20%3Cpolygon%20points%3D%22281%2C166%20329%2C190%20329%2C460%20281%2C477%22%2F%3E%20%3Cpolygon%20points%3D%22351%2C193%20472%2C193%20472%2C456%20351%2C456%22%2F%3E%20%3Cpolygon%20points%3D%22727%2C193%20849%2C193%20849%2C456%20727%2C456%22%2F%3E%20%3Cpolygon%20points%3D%22872%2C189%20917%2C166%20917%2C477%20872%2C460%22%2F%3E%20%3Cpolygon%20points%3D%221088%2C65%201200%2C0%201200%2C587%201088%2C547%22%2F%3E%20%3C%2Fg%3E%20%3C%2Fsvg%3E");
    mask-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221200%22%20height%3D%22669%22%20viewBox%3D%220%200%201200%20669%22%3E%20%3Cdefs%3E%20%3Cmask%20id%3D%22paper-handles%22%20maskUnits%3D%22userSpaceOnUse%22%20x%3D%220%22%20y%3D%220%22%20width%3D%221200%22%20height%3D%22669%22%20style%3D%22mask-type%3Aluminance%22%3E%20%3Crect%20width%3D%221200%22%20height%3D%22669%22%20fill%3D%22white%22%2F%3E%20%3Cg%20fill%3D%22black%22%3E%20%3Cellipse%20cx%3D%2299%22%20cy%3D%22333%22%20rx%3D%228%22%20ry%3D%2214%22%2F%3E%20%3Cellipse%20cx%3D%22325%22%20cy%3D%22343%22%20rx%3D%223%22%20ry%3D%228%22%2F%3E%20%3Cellipse%20cx%3D%22458%22%20cy%3D%22344%22%20rx%3D%227%22%20ry%3D%228%22%2F%3E%20%3Cellipse%20cx%3D%22741%22%20cy%3D%22344%22%20rx%3D%227%22%20ry%3D%228%22%2F%3E%20%3Cellipse%20cx%3D%22912%22%20cy%3D%22343%22%20rx%3D%223%22%20ry%3D%2210%22%2F%3E%20%3Cellipse%20cx%3D%221101%22%20cy%3D%22335%22%20rx%3D%228%22%20ry%3D%2214%22%2F%3E%20%3C%2Fg%3E%20%3C%2Fmask%3E%20%3C%2Fdefs%3E%20%3Cg%20fill%3D%22white%22%20mask%3D%22url(%23paper-handles)%22%3E%20%3Cpolygon%20points%3D%220%2C0%20115%2C65%20114%2C547%200%2C587%22%2F%3E%20%3Cpolygon%20points%3D%22281%2C166%20329%2C190%20329%2C460%20281%2C477%22%2F%3E%20%3Cpolygon%20points%3D%22351%2C193%20472%2C193%20472%2C456%20351%2C456%22%2F%3E%20%3Cpolygon%20points%3D%22727%2C193%20849%2C193%20849%2C456%20727%2C456%22%2F%3E%20%3Cpolygon%20points%3D%22872%2C189%20917%2C166%20917%2C477%20872%2C460%22%2F%3E%20%3Cpolygon%20points%3D%221088%2C65%201200%2C0%201200%2C587%201088%2C547%22%2F%3E%20%3C%2Fg%3E%20%3C%2Fsvg%3E");
    -webkit-mask-size:cover; mask-size:cover;
    -webkit-mask-position:center; mask-position:center;
    -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
    mask-mode:alpha;
  }
  .light-evening .home-wallpaper,
  .light-night .home-wallpaper{
    -webkit-mask-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221200%22%20height%3D%22669%22%20viewBox%3D%220%200%201200%20669%22%3E%20%3Cdefs%3E%20%3Cmask%20id%3D%22paper-handles%22%20maskUnits%3D%22userSpaceOnUse%22%20x%3D%220%22%20y%3D%220%22%20width%3D%221200%22%20height%3D%22669%22%20style%3D%22mask-type%3Aluminance%22%3E%20%3Crect%20width%3D%221200%22%20height%3D%22669%22%20fill%3D%22white%22%2F%3E%20%3Cg%20fill%3D%22black%22%3E%20%3Cellipse%20cx%3D%2299%22%20cy%3D%22346%22%20rx%3D%228%22%20ry%3D%2214%22%2F%3E%20%3Cellipse%20cx%3D%22325%22%20cy%3D%22356%22%20rx%3D%223%22%20ry%3D%228%22%2F%3E%20%3Cellipse%20cx%3D%22458%22%20cy%3D%22357%22%20rx%3D%227%22%20ry%3D%228%22%2F%3E%20%3Cellipse%20cx%3D%22741%22%20cy%3D%22357%22%20rx%3D%227%22%20ry%3D%228%22%2F%3E%20%3Cellipse%20cx%3D%22912%22%20cy%3D%22356%22%20rx%3D%223%22%20ry%3D%2210%22%2F%3E%20%3Cellipse%20cx%3D%221101%22%20cy%3D%22348%22%20rx%3D%228%22%20ry%3D%2214%22%2F%3E%20%3C%2Fg%3E%20%3C%2Fmask%3E%20%3C%2Fdefs%3E%20%3Cg%20fill%3D%22white%22%20mask%3D%22url(%23paper-handles)%22%3E%20%3Cpolygon%20points%3D%220%2C16%20115%2C79%20114%2C560%200%2C599%22%2F%3E%20%3Cpolygon%20points%3D%22281%2C179%20329%2C203%20329%2C473%20281%2C490%22%2F%3E%20%3Cpolygon%20points%3D%22351%2C206%20472%2C206%20472%2C469%20351%2C469%22%2F%3E%20%3Cpolygon%20points%3D%22727%2C206%20849%2C206%20849%2C469%20727%2C469%22%2F%3E%20%3Cpolygon%20points%3D%22872%2C202%20917%2C179%20917%2C490%20872%2C473%22%2F%3E%20%3Cpolygon%20points%3D%221088%2C79%201200%2C16%201200%2C599%201088%2C560%22%2F%3E%20%3C%2Fg%3E%20%3C%2Fsvg%3E");
    mask-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221200%22%20height%3D%22669%22%20viewBox%3D%220%200%201200%20669%22%3E%20%3Cdefs%3E%20%3Cmask%20id%3D%22paper-handles%22%20maskUnits%3D%22userSpaceOnUse%22%20x%3D%220%22%20y%3D%220%22%20width%3D%221200%22%20height%3D%22669%22%20style%3D%22mask-type%3Aluminance%22%3E%20%3Crect%20width%3D%221200%22%20height%3D%22669%22%20fill%3D%22white%22%2F%3E%20%3Cg%20fill%3D%22black%22%3E%20%3Cellipse%20cx%3D%2299%22%20cy%3D%22346%22%20rx%3D%228%22%20ry%3D%2214%22%2F%3E%20%3Cellipse%20cx%3D%22325%22%20cy%3D%22356%22%20rx%3D%223%22%20ry%3D%228%22%2F%3E%20%3Cellipse%20cx%3D%22458%22%20cy%3D%22357%22%20rx%3D%227%22%20ry%3D%228%22%2F%3E%20%3Cellipse%20cx%3D%22741%22%20cy%3D%22357%22%20rx%3D%227%22%20ry%3D%228%22%2F%3E%20%3Cellipse%20cx%3D%22912%22%20cy%3D%22356%22%20rx%3D%223%22%20ry%3D%2210%22%2F%3E%20%3Cellipse%20cx%3D%221101%22%20cy%3D%22348%22%20rx%3D%228%22%20ry%3D%2214%22%2F%3E%20%3C%2Fg%3E%20%3C%2Fmask%3E%20%3C%2Fdefs%3E%20%3Cg%20fill%3D%22white%22%20mask%3D%22url(%23paper-handles)%22%3E%20%3Cpolygon%20points%3D%220%2C16%20115%2C79%20114%2C560%200%2C599%22%2F%3E%20%3Cpolygon%20points%3D%22281%2C179%20329%2C203%20329%2C473%20281%2C490%22%2F%3E%20%3Cpolygon%20points%3D%22351%2C206%20472%2C206%20472%2C469%20351%2C469%22%2F%3E%20%3Cpolygon%20points%3D%22727%2C206%20849%2C206%20849%2C469%20727%2C469%22%2F%3E%20%3Cpolygon%20points%3D%22872%2C202%20917%2C179%20917%2C490%20872%2C473%22%2F%3E%20%3Cpolygon%20points%3D%221088%2C79%201200%2C16%201200%2C599%201088%2C560%22%2F%3E%20%3C%2Fg%3E%20%3C%2Fsvg%3E");
  }
  /* A pale sheet laid on the panel instead of multiplied into it. Kept under
     full opacity so the panel's own lighting still reads through it, which is
     what multiply was giving the dark patterns for free. */
  .home-wallpaper.blend-normal{mix-blend-mode:normal; opacity:.82}
  .home-wallpaper-art{width:100%; height:100%; display:block}
  .debug-banner{
    display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
    gap:6px 16px; padding:6px 12px; color:#fff0cf; background:#442809;
    border-bottom:2px solid #e9ad4c; font:14px/1.4 system-ui,sans-serif;
  }
  .debug-banner[hidden]{display:none}
  .debug-banner button{
    min-height:44px; padding:6px 14px; border:1px solid #e9ad4c;
    border-radius:8px; color:#fff0cf; background:#281907; cursor:pointer;
    font:inherit;
  }
  /* A third of the wall per repeat. See wallpaperSvg in home-decor.js: the
     sheet holds about thirteen motifs, so this lands them near life size
     instead of one sheet stretched across the whole room. */
  .home-wallpaper-art.is-raster{background-repeat:repeat; background-size:34% auto}
  .home-swatch{
    display:block; width:100%; height:52px; overflow:hidden; border-radius:6px;
    background:#e8dabd;
  }
  .home-swatch.is-plain{background:linear-gradient(160deg,#efe3c8,#d9c7a6)}
  .home-swatch .home-wallpaper-art{height:52px}
  /* What the map owes a returning learner: the shift they left half-done, and
     how the day stands. Both were being tracked and neither was ever shown. */
  .map-resume{margin-top:6px}
  .map-day-status{
    margin:8px 0 0; font-size:.8rem; color:#e3c48c; opacity:.9; text-align:center;
  }
  .map-day-status[hidden]{display:none}

  /* ---- Ink that was chosen for a light panel and used on a dark one ----
     .ink-on-dark-fixes

     Three tokens are set for the cream workspace: --ai-indigo on .btn-ghost,
     --momiji on the encounter counter, --moss on the English how-to line. The
     Inn and the Entrance put a dark bar and a dark stage under some of them,
     and the map's detail panel is near-black. Measured before changing:

       map practice button   navy on near-black       1.28:1
       encounter counter     red-orange on brown      3.25:1
       how-to line           sage green on cream      2.76:1

     The tokens are right where they were designed to sit; only these
     placements move.

     Not every ghost button on the bar is transparent: `Restart from Learn`
     carries its own cream background, so lightening its ink by position made
     near-white text on cream - readable before, 1.07:1 after. Anything with a
     surface of its own keeps the ink that suits that surface. */

  .inn-stage .stage-bar .btn-ghost:not(.stage-restart),
  .entrance-stage .stage-bar .btn-ghost:not(.stage-restart),
  #map-detail-practice{
    color:#f7ecd8;
    border-color:rgba(247,215,159,.42);
  }
  .inn-stage .stage-bar .btn-ghost:not(.stage-restart):hover,
  .entrance-stage .stage-bar .btn-ghost:not(.stage-restart):hover,
  #map-detail-practice:hover{background:rgba(255,240,207,.14)}

  /* The counter sits on the bar, so it takes the bar's light ink rather than
     the momiji it uses on cream. */
  .inn-stage .encounter-status,
  .entrance-stage .encounter-status{color:#f3c9a5}

  /* The English instruction is the one line a learner has to read to know what
     to do, and sage green on cream was the faintest thing on the screen. */
  .meaning-line{color:#3f6b46}

  /* Kon's speech bubble is near-white and keeps its own background wherever it
     goes, so on the dark home stage it inherited that stage's light ink and
     wrote near-white on near-white: 1.08:1, an apparently empty bubble on the
     one screen a returning learner lands on. The panel sets its own dark ink
     rather than taking the stage's; the lines inside that carry their own
     colour still win. */
  #screen-game.home-stage #dialogue-panel{color:#2d2926}

/* Touch targets on the reward stage.
 *
 * The placement targets were raised to 44px, but the chrome around them was
 * missed: at 375px the two menu buttons were 35px tall, the overflow items 33,
 * the scene-back link 32, the shop's category tabs 35, and the audio button
 * 33x29 - under on both axes. Every one of them is an ordinary button in a
 * flow layout, so unlike the Inn's illustrated hotspots they can simply be
 * made bigger; nothing here is positioned against a painting.
 *
 * Gated on a coarse pointer so the desktop layout keeps its proportions. The
 * buttons grow by min-height rather than padding, so a control that already
 * clears 44px is untouched. */
@media (pointer: coarse){
  .home-menu-button,
  .home-yard-more button,
  .home-scene-back,
  .home-shop-chrome button,
  .home-howto,
  .home-tab{
    min-height:44px;
  }
  .breadcrumb,
  #romaji-switch,
  .hint-btn{
    min-height:44px;
  }
  #romaji-switch{
    width:44px;
    min-width:44px;
    height:44px;
    background:transparent;
  }
  #romaji-switch::before{
    width:34px;
    height:19px;
    background:rgba(27,42,74,0.22);
  }
  #romaji-switch.on::before{background:var(--moss)}
  #romaji-switch::after{top:14px;left:7px}
  .home-yard-more summary{
    width:44px;
    height:44px;
  }
  /* Not reward-stage-only: the dialogue's audio button is shared by every
     stage, and it was the smallest control in the app. */
  #speak-btn{
    min-width:44px;
    min-height:44px;
  }
}

/* ---- Phone size floor (v444) ----
   Measured at 360, 390 and 430px wide: nothing scrolled sideways, but several
   labels were 9-10px and several controls were smaller to hit than a finger.
   Text here is held at 11px or more; controls get a 44px hit area, drawn or
   invisible, so nothing that looks small has to move to be easy to press. */
.speak-btn{position:relative}
.speak-btn::before{content:"";position:absolute;inset:-9px -7px}
.switch::before{width:44px;height:44px}
@media(max-width:760px){
  .metric-gloss{font-size:11px}
  .screen-gloss,.map-heading .screen-gloss{font-size:11px}
  .map-destination-label{font-size:11px}
  .inn-journey-status{font-size:11px}
  .romaji-toggle,.inn-stage .romaji-toggle,.entrance-stage .romaji-toggle{font-size:11px}
  .inn-stage .inn-focus-cue:not([hidden]){font-size:11px}
  .inn-stage .inn-new-word-kicker{font-size:11px;letter-spacing:.08em}
  .inn-stage .inn-shift-beat{font-size:11px}
  .stage-restart{min-height:44px;padding-inline:12px}
  /* The "1 Read Kon's request" pill and the romaji switch shared one line and
     ran into each other at 360px. The switch takes its own row instead. */
  .inn-stage .romaji-toggle{position:static;justify-content:flex-end;margin:0 0 6px}
  /* The continue marker sat under the speaker button in the same corner. The
     bubble keeps its right padding clear, so the marker goes top-right. */
  .inn-stage .dialogue-continue{top:8px;bottom:auto;right:6px}
  /* The entrance bubble had the same collision: the marker sat inside the
     speaker button, so tapping it played audio instead of continuing. */
  .entrance-stage .dialogue-continue{top:8px;bottom:auto;right:6px}
  /* The room's drop spots follow the painting, and a few are thin strips on a
     phone. Each is given room to hit in the direction nothing else is. */
  /* z-index:-1 keeps the widened hit area under the zone's own contents. On
     top of them (v444-v452) it covered the old towel, bulb and sheet that sit
     inside their zones, and a finger could no longer pick them up. */
  .inn-room-illustrated .inn-drop-zone::after{content:"";position:absolute;z-index:-1;top:var(--hit-t,0);right:var(--hit-r,0);bottom:var(--hit-b,0);left:var(--hit-l,0)}
  .inn-room-illustrated .inn-drop-zone[data-key="remove-recycle"]{--hit-r:-19px;--hit-t:-2px}
  .inn-room-illustrated .inn-drop-zone[data-key="stove"]{--hit-t:-27px;--hit-b:-2px}
  .inn-room-illustrated .inn-drop-zone[data-key="microwave"]{--hit-t:-2px;--hit-b:-20px}
  .inn-room-illustrated .inn-drop-zone[data-key="g1"],
  .inn-room-illustrated .inn-drop-zone[data-key="g2"]{--hit-t:-5px;--hit-b:-6px}
  /* The rest of the small print, found by the same measurement. */
  .inn-journey-label,.build-stamp,.entrance-stage .narration,.entrance-stage .player-caption,
  #map-progress-text,.map-detail-status,.map-detail-focus,.inn-caption,.inn-reward-kicker,
  .listen-again,.answer-workspace .inn-caption,.inn-room-illustrated .inn-caption{font-size:11px}
  #btn-back-map,#btn-title-menu,#hint-btn,.map-detail-action,#btn-reward-home{min-height:44px}
  #btn-title-menu{min-width:44px}
  /* Drawn small on purpose; hit at full size. */
  .listen-again{position:relative}
  .inn-stage .listen-again{position:absolute}
  .listen-again::before{content:"";position:absolute;inset:-6px 0}
  button.inn-placed-object{position:relative}
  button.inn-placed-object::before{content:"";position:absolute;inset:-8px}
  /* Home and word board, from the second measurement pass. */
  .job-state,.home-pan-hint,.home-scene-back,.home-card-sub,
  .home-stage .home-shelf .home-card-sub{font-size:11px}
  .home-scene-back{min-height:44px;min-width:44px}
  .home-menu-button,.home-tab,.home-shop-chrome button,.home-howto,.home-yard-more button{min-height:44px}
  /* Kon's text keeps clear of the top-right continue marker. */
  .inn-stage .dialogue.entrance-dialogue .speech{padding-right:38px}
}

/* On a 320px screen the long romaji label reached behind Kon's name tab.
   This belongs after the shared learning-context spacing rules above so their
   mobile margin cannot pull the speaker tab back into the romaji row. */
@media(max-width:340px){
  .entrance-stage .romaji-toggle{position:static;justify-content:flex-end;margin:0 0 38px}
  .entrance-stage .learning-context{padding-top:20px}
  /* Kon's longer lines fill so many rows this narrow that the narration above
     them covered the characters by 80-130px. Kon's own line tells the story. */
  .entrance-stage .narration{display:none}
}
/* At 360px Kon's longest line left the narration 3px over the あなた label.
   A tighter strip clears it. */
@media(max-width:360px){
  .entrance-stage .narration{bottom:calc(100% + 3px);padding-top:5px;padding-bottom:5px}
}
/* The map labels grew to 11px, and Kon's marker, which sits just above the
   place point, covered the top of 「路地の入口」. It is lifted to clear it. */
@media(max-width:760px){
  .map-kon-marker{transform:translate(-50%,-140%)}
  .map-kon-marker.is-traveling{transform:translate(-50%,-140%) scale(1.12)}
}
/* At 400px and under, five journey stops cannot fit a lamp beside each
   label at 11px ("Shif..."), so the lamp sits above the label instead. */
@media(max-width:400px){
  .inn-journey-stop{grid-template-columns:1fr;grid-template-areas:"lamp" "label" "reward";justify-items:center;row-gap:2px}
  .inn-journey-label{overflow:visible;text-overflow:clip}
}

/* Illustrated room targets follow the artwork's proportions, so some are
   smaller than a finger on a phone. Keep their visual footprint, but extend
   the button's hit area invisibly. Once an object is chosen, name every valid
   place so the learner can act without guessing what a small drawing means. */
@media(max-width:760px){
  .inn-room-illustrated .inn-hotspot::before{content:"";position:absolute;inset:-10px;z-index:-1}
  .inn-room-illustrated .inn-scene-zones.awaiting-drop .inn-hotspot > .inn-caption{opacity:1;transform:translate(-50%,0)}
  .inn-room-illustrated [data-key="remove-recycle"] > .inn-caption{top:calc(100% + 5px);bottom:auto}
}

/* The running build, shown only in debug mode beside the banner text. */
.debug-build{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.72rem;
  opacity:.85;white-space:nowrap}

/* ---- The shift board (Episode 1) ----
   Guests wait as wooden room tags with a patience bar; Kon's desk jobs are
   paper memos with none. Near the limit a guest turns red and pulses, then
   shakes, and the edge of the screen pulses red while anyone is close. */
.shift-board{display:flex;flex-direction:column;gap:14px;padding:12px}
.shift-board .shift-hud{order:-1}
.shift-hud{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;padding:10px 14px;border-radius:12px;
  background:linear-gradient(180deg,#5b3b22,#3c2614);color:var(--washi);box-shadow:0 4px 12px rgba(0,0,0,.35)}
.shift-clock{font-family:"Shippori Mincho","Hiragino Mincho ProN",serif;font-size:26px;font-weight:800;color:var(--lantern-bright);letter-spacing:.04em}
.shift-clock-box{display:flex;align-items:center;gap:8px}
.shift-clock-label{display:flex;flex-direction:column;font-size:12px;font-weight:700;color:#ecd2a2;line-height:1.2}
.shift-clock-label small{font-size:11px;font-weight:600;color:rgba(242,235,221,.75)}
.shift-lamps{display:flex;gap:5px}
.shift-lamps span{width:11px;height:15px;border-radius:5px 5px 4px 4px;background:rgba(255,255,255,.12);box-shadow:inset 0 0 0 1px rgba(255,255,255,.18)}
.shift-lamps span.lit{background:radial-gradient(circle at 50% 40%,#fff3c4,var(--lantern) 70%);box-shadow:0 0 8px rgba(247,200,119,.8)}
.shift-served,.shift-level{font-size:12px;color:#ecd2a2}
.shift-served b{font-size:15px;color:var(--washi)}
.shift-level{margin-left:auto;padding:2px 10px;border:1px solid rgba(242,235,221,.35);border-radius:10px}
.shift-section{display:flex;flex-direction:column;gap:8px}
.shift-heading{margin:0;font-size:15px;color:var(--washi)}
.shift-heading small{margin-left:6px;font-size:12px;font-weight:400;color:var(--text-dim)}
.shift-empty,.shift-strip-empty{margin:0;padding:10px 12px;border-radius:10px;background:rgba(14,24,48,.55);font-size:13px;color:var(--text-dim)}
.shift-tags{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}
.shift-tag{position:relative;display:flex;flex-direction:column;align-items:stretch;gap:6px;min-height:150px;padding:16px 10px 10px;border:0;border-radius:10px 10px 14px 14px;
  background:linear-gradient(180deg,#9a6a40,#744a2b 60%,#5d3a22);color:#fff3dc;text-align:left;font:inherit;cursor:pointer;
  box-shadow:inset 0 1px 0 rgba(255,225,170,.35),inset 0 -3px 0 rgba(0,0,0,.25),0 6px 14px rgba(0,0,0,.4)}
.shift-tag::before{content:"";position:absolute;left:50%;top:6px;width:9px;height:9px;margin-left:-4.5px;border-radius:50%;background:var(--ai-indigo-deep)}
.shift-tag:active{transform:translateY(2px)}
.shift-room{font-family:"Shippori Mincho","Hiragino Mincho ProN",serif;font-size:22px;font-weight:800;line-height:1}
.shift-who{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:700;color:#f6ddb0}
.shift-face{display:inline-grid;place-items:center;flex:0 0 auto;width:34px;height:34px;overflow:hidden;border-radius:50%;
  background:radial-gradient(circle at 50% 35%,#6a4630,#3c2614);border:2px solid rgba(247,200,119,.7);font-size:11px;font-weight:800;color:#fff3dc}
.shift-face img{width:100%;height:100%;object-fit:cover}
.shift-tag .shift-face{width:52px;height:52px}
.shift-mine .shift-face{width:40px;height:40px}
.shift-face-kon{background:url("assets/fox/fox-neutral-idle-transparent-v2.webp") center/cover,#3c2614}
.shift-slip{flex:1;padding:6px 8px;border-radius:3px;background:var(--washi);color:var(--sumi);font-size:13px;line-height:1.45}
.shift-call{background:#1f2740;color:#dce8ff;font-weight:700}
.shift-bar{position:relative;display:block;height:8px;border-radius:4px;background:rgba(0,0,0,.35)}
.shift-bar i{position:absolute;left:0;top:0;bottom:0;border-radius:4px;background:var(--moss);transition:width 1s linear}
.shift-mood{font-size:11px;font-weight:700;color:#bfe0c4}
.shift-mood.restless{color:#f2c46a}
.shift-mood.angry,.shift-mood.late{color:#ffb3a0}
.shift-count{display:none}
.shift-memos{display:flex;flex-direction:column;gap:8px}
.shift-memo{display:flex;flex-direction:column;gap:4px;min-height:44px;padding:10px 12px;border:0;border-radius:4px;background:var(--washi);color:var(--sumi);
  text-align:left;font:inherit;font-size:14px;line-height:1.5;cursor:pointer;box-shadow:0 3px 8px rgba(0,0,0,.35)}
.shift-memo-from{font-size:11px;font-weight:800;color:var(--momiji)}
/* Urgent: red and pulsing, with a countdown. Critical: faster, and shaking. */
.shift-tag.urgent,.shift-mini.urgent,.shift-tag.critical,.shift-mini.critical{background:linear-gradient(180deg,#b0603f,#86402a 60%,#6a2f1e);animation:shift-urgent 1.3s ease-in-out infinite}
.shift-tag.critical,.shift-mini.critical{animation:shift-urgent .7s ease-in-out infinite,shift-jitter 2.2s ease-in-out infinite}
.shift-tag.urgent .shift-bar i,.shift-tag.critical .shift-bar i,.shift-mini.urgent .shift-bar i,.shift-mini.critical .shift-bar i,
.shift-mine.urgent .shift-bar i,.shift-mine.critical .shift-bar i{background:#e0654a;animation:shift-blink .7s steps(2,start) infinite}
.shift-tag.urgent .shift-count,.shift-tag.critical .shift-count{display:grid;place-items:center;position:absolute;top:-10px;right:-8px;z-index:2;height:32px;padding:0 9px;
  border-radius:16px;background:#d64d34;color:#fff;font-size:14px;font-weight:900;white-space:nowrap;box-shadow:0 0 0 3px #fff3dc,0 4px 10px rgba(0,0,0,.5)}
.shift-tag.critical .shift-count{background:#ff2e12;animation:shift-beat .6s ease-in-out infinite}
.shift-count:empty{display:none!important}
.shift-tag.late{box-shadow:0 0 0 2px var(--momiji),0 6px 14px rgba(0,0,0,.4)}
@keyframes shift-urgent{0%,100%{box-shadow:0 0 0 2px rgba(214,77,52,.9),0 6px 14px rgba(0,0,0,.4)}50%{box-shadow:0 0 0 5px rgba(214,77,52,.35),0 0 22px rgba(214,77,52,.6)}}
@keyframes shift-jitter{0%,82%,100%{transform:none}86%{transform:rotate(-3deg)}90%{transform:rotate(3deg)}94%{transform:rotate(-2deg)}}
@keyframes shift-blink{50%{opacity:.25}}
@keyframes shift-beat{0%,100%{transform:scale(1)}50%{transform:scale(1.15)}}
#screen-game::after{content:"";position:fixed;inset:0;z-index:38;pointer-events:none;opacity:0;transition:opacity .4s;
  box-shadow:inset 0 0 0 4px rgba(214,77,52,.9),inset 0 0 60px 10px rgba(214,77,52,.5)}
#screen-game.shift-alarm::after{opacity:1;animation:shift-edge 1.3s ease-in-out infinite}
#screen-game.shift-alarm-hi::after{animation-duration:.7s}
@keyframes shift-edge{50%{opacity:.35}}
/* While a question is open: who else is waiting, and this guest's own bar. */
.shift-strip{display:flex;align-items:center;gap:8px;overflow-x:auto;padding:2px 0 4px;scrollbar-width:none}
.shift-strip::-webkit-scrollbar{display:none}
.shift-strip-label{flex:0 0 auto;font-size:12px;color:#d9c29a}
.shift-mini{flex:0 0 auto;display:grid;grid-template-columns:auto 1fr auto;gap:2px 6px;align-items:center;min-width:118px;min-height:44px;padding:6px 8px;border:0;border-radius:8px;
  background:linear-gradient(180deg,#8a5a35,#5d3a22);color:#fff3dc;text-align:left;font:inherit;cursor:pointer}
.shift-mini b{font-size:14px}
.shift-mini .shift-bar{grid-column:1/-1;height:6px}
.shift-mini.urgent .shift-mood,.shift-mini.critical .shift-mood{display:none}
.shift-mini.urgent .shift-count,.shift-mini.critical .shift-count{display:inline-block;padding:1px 7px;border-radius:10px;background:#fff3dc;color:#b3261e;font-size:12px;font-weight:900}
.shift-mini-desk{background:var(--washi);color:var(--sumi)}
.shift-mini.late{box-shadow:0 0 0 2px var(--momiji)}
.shift-mine{display:grid;grid-template-columns:auto auto 1fr auto auto;gap:8px;align-items:center;padding:6px 10px;border-radius:8px;background:rgba(14,24,48,.72);color:#fff3dc;font-size:12px}
.shift-mine b{white-space:nowrap}
.shift-mine.urgent,.shift-mine.critical{background:rgba(120,30,20,.85);box-shadow:0 0 0 2px #d64d34}
.shift-mine.urgent .shift-count,.shift-mine.critical .shift-count{display:inline-block;padding:1px 7px;border-radius:10px;background:#fff3dc;color:#b3261e;font-weight:900}
.shift-mine.served .shift-face{animation:shift-hop .5s ease-out 2}
.shift-mine.served-miss .shift-face{animation:shift-jitter .6s ease-in-out}
.shift-mine.shift-mine-desk{display:flex;gap:8px;align-items:center}
@keyframes shift-hop{50%{transform:translateY(-6px)}}
.shift-back{align-self:flex-start;min-height:44px;padding:0 14px;border:1px solid rgba(242,235,221,.35);border-radius:22px;background:rgba(14,24,48,.6);color:var(--washi);font:inherit;font-size:13px;cursor:pointer}
/* Warnings: above the answers, at most two, one per guest. */
.shift-toasts{position:fixed;left:50%;bottom:calc(84px + env(safe-area-inset-bottom,0px));z-index:40;transform:translateX(-50%);display:flex;flex-direction:column;align-items:center;gap:6px;max-width:92vw;pointer-events:none}
.shift-toast{max-width:92vw;padding:8px 14px;border-radius:22px;background:#9c4a2f;color:#fff;font-size:13px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;box-shadow:0 6px 16px rgba(0,0,0,.4)}
.shift-toast.hot{background:#b3261e;font-size:14px;animation:shift-beat .6s ease-in-out 3}
.shift-toast.tea{background:#4f7a5a}
.shift-paused{position:fixed;inset:0;z-index:60;display:grid;place-items:center;background:rgba(8,15,33,.78)}
.shift-paused-card{display:grid;gap:14px;justify-items:center;padding:22px 28px;border-radius:14px;background:var(--washi);color:var(--sumi);font-size:18px;font-weight:800}
.shift-paused-card p{margin:0}
/* Difficulty, chosen once before the evening starts. */
.shift-level-card{gap:10px}
.shift-level-en{margin:-6px 0 4px;font-size:12px;color:#8a5a35}
.shift-level-option{display:grid;grid-template-columns:auto 1fr;gap:2px 10px;align-items:baseline;width:100%;min-height:44px;padding:12px 14px;border:2px solid var(--washi-dim);border-radius:12px;
  background:#fffaf0;color:var(--sumi);text-align:left;font:inherit;cursor:pointer}
.shift-level-option b{font-size:19px}
.shift-level-option span{font-size:12px;color:#8a5a35}
.shift-level-option small{grid-column:1/-1;font-size:12px;color:#5d3a22}
.shift-level-hard{border-color:#c8573f}.shift-level-normal{border-color:#e0a33e}.shift-level-easy{border-color:#6f9a78}
.shift-tea-note{margin:4px 0 0;font-size:12px;line-height:1.55;color:#5d3a22}
/* The evening's result: fireworks, what the guests said, the rank. */
.shift-result{position:relative;overflow:hidden}
.shift-sky{position:absolute;inset:0;pointer-events:none}
.shift-burst{position:absolute;width:4px;height:4px;border-radius:50%;color:var(--burst);opacity:0;
  box-shadow:0 -40px 0 1px,28px -28px 0 1px,40px 0 0 1px,28px 28px 0 1px,0 40px 0 1px,-28px 28px 0 1px,-40px 0 0 1px,-28px -28px 0 1px;
  animation:shift-burst 2.7s ease-out infinite}
@keyframes shift-burst{0%{transform:scale(.2);opacity:0}15%{opacity:1}70%{opacity:.9}100%{transform:scale(1.4);opacity:0}}
.shift-voice{position:relative;display:flex;align-items:center;gap:10px;margin:6px 0;font-size:15px;line-height:1.6;color:var(--sumi);text-align:left}
.shift-voice p{margin:0}
.shift-voice .shift-face{width:52px;height:52px}
.shift-voice small{display:block;font-size:12px;color:#8a5a35}
.shift-rank{position:relative;display:flex;align-items:center;gap:14px;margin:12px 0 0;padding:10px 14px;border-radius:12px;background:rgba(255,250,240,.95);color:var(--sumi)}
.shift-seal{display:grid;place-items:center;flex:0 0 auto;width:54px;height:54px;border:3px solid var(--momiji);border-radius:50%;color:var(--momiji);
  font-family:"Shippori Mincho","Hiragino Mincho ProN",serif;font-size:26px;font-weight:900;transform:rotate(-8deg)}
.shift-rank b{display:block;font-size:16px}
.shift-rank small{display:block;font-size:12px;color:#5d3a22}
.shift-tally{position:relative;display:flex;justify-content:space-around;margin:12px 0 4px;text-align:center}
.shift-tally b{display:block;font-size:22px;color:var(--sumi)}
.shift-tally span{font-size:12px;color:#5d3a22}
.shift-next-note{position:relative;margin:6px 0;font-size:13px;color:var(--momiji)}
@media (prefers-reduced-motion:reduce){
  .shift-tag,.shift-mini,.shift-count,.shift-bar i,.shift-toast,.shift-burst,#screen-game::after{animation:none!important}
}
@media(max-width:520px){
  .shift-tags{grid-template-columns:1fr 1fr;gap:10px}
  .shift-tag{min-height:140px;padding:14px 8px 8px}
  .shift-room{font-size:20px}
  .shift-mine{grid-template-columns:auto 1fr auto;grid-template-areas:"face name count" "bar bar mood"}
  .shift-mine .shift-face{grid-area:face}
  .shift-mine b{grid-area:name;overflow:hidden;text-overflow:ellipsis}
  .shift-mine .shift-bar{grid-area:bar}
  .shift-mine .shift-mood{grid-area:mood}
  .shift-mine .shift-count{grid-area:count}
}

/* Old things to take away - the towel, the bulb, the sheet - are picked out
   with a soft glow, and the bulb fills its taller spot. */
.inn-room-illustrated button.inn-placed-object{box-shadow:0 0 0 2px rgba(255,214,140,.85),0 0 10px rgba(255,200,110,.55)}
.answer-workspace .inn-room-illustrated .inn-drop-zone[data-key="install-bulb"] > .inn-placed-object{width:100%;max-width:none}

/* Kon's first-time tips on the shift board. */
.shift-coach{position:fixed;left:12px;right:12px;bottom:calc(16px + env(safe-area-inset-bottom,0px));z-index:55;display:grid;grid-template-columns:56px 1fr;gap:10px;align-items:start;
  max-width:460px;margin:0 auto;padding:12px;border-radius:14px;background:var(--washi);color:var(--sumi);box-shadow:0 10px 26px rgba(0,0,0,.55)}
.shift-coach img{width:56px;height:56px;object-fit:contain}
.shift-coach p{margin:0}
.shift-coach-jp{font-size:15px;font-weight:700;line-height:1.55}
.shift-coach-en{margin:4px 0 10px!important;font-size:12px;line-height:1.45;color:#5d3a22}
.shift-coach-target{position:relative;z-index:44;outline:3px solid var(--lantern-bright);outline-offset:3px;animation:shift-coach-pulse 1.4s ease-in-out infinite}
@keyframes shift-coach-pulse{50%{outline-color:rgba(247,200,119,.35)}}

/* 「・第一話まで あと12問」 beside the day's counter during the three days. */
.to-episode{margin-left:4px;color:var(--lantern-bright);font-weight:700}
.to-episode[hidden]{display:none}

/* Episode 1's word list teaches its new words: each has its example sentence
   and a button to hear it. */
.job-example{display:flex;align-items:center;gap:6px;margin-top:4px;font-size:13px;line-height:1.5;color:var(--sumi)}
.job-example-text{flex:1;min-width:0}
.job-example b{color:var(--momiji)}
.job-say{flex:0 0 auto;min-width:44px;min-height:44px;border:1px solid #d8c29a;border-radius:22px;background:#fffaf0;font-size:16px;cursor:pointer}

/* ---- The room on a phone ----
   Drawn to fit a 390px screen, the whole room was about 340x230px: the stove
   and microwave a finger apart, the burned-out bulb smaller than a fingertip
   and the used towel's stains invisible. On a phone the painting is shown half
   as large again and swipes sideways; the empty ceiling and the foreground
   floor are cropped, so it is no taller than before. It opens on the part of
   the room the request is about (centerRoomOnTask). */
.inn-room-canvas{position:absolute;inset:0}
.inn-room-swipe{display:none}
@media(max-width:520px){
  .inn-room-illustrated .inn-room-viewport{aspect-ratio:137/100;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;overscroll-behavior-x:contain}
  .inn-room-illustrated .inn-room-viewport::-webkit-scrollbar{display:none}
  /* 150% wide and 3:2, showing its middle 73% from 12% down. */
  .inn-room-illustrated .inn-room-canvas{inset:auto;left:0;top:-16.438%;width:150%;height:136.986%}
  /* The room's light moves with the painting, not the window onto it. */
  .inn-room-illustrated .inn-room-viewport::before,.inn-room-illustrated .inn-room-viewport::after{display:none}
  .inn-room-illustrated .inn-room-canvas::before,.inn-room-illustrated .inn-room-canvas::after{content:"";position:absolute;inset:0;z-index:1;opacity:0;pointer-events:none}
  .inn-room-illustrated .inn-room-canvas::before{background:rgba(7,15,29,.48);transition:opacity .5s cubic-bezier(.22,1,.36,1)}
  .inn-room-illustrated .inn-room-canvas::after{background:radial-gradient(circle at 50.5% 22%,rgba(255,226,143,.72) 0,rgba(248,188,82,.34) 9%,rgba(248,177,60,.08) 24%,transparent 42%)}
  .room-light-dim .inn-room-canvas::before{opacity:1}
  .room-light-bright .inn-room-canvas::after{animation:room-light-warm .65s cubic-bezier(.22,1,.36,1) forwards}
  .inn-room-swipe{display:block;margin:0;padding:4px 10px;background:rgba(36,24,14,.92);color:#f0c98a;font-size:11px;text-align:center}
}
/* Old things to take away say what they are without being picked up first,
   and the used towel looks used: its painted stains vanished at phone size. */
.inn-room-illustrated button.inn-placed-object{overflow:visible}
.inn-room-illustrated button.inn-placed-object > .inn-caption{opacity:1;z-index:3;top:auto;bottom:2px;transform:translate(-50%,0);background:rgba(43,28,16,.86);color:#fff3dc;white-space:nowrap}
.inn-room-illustrated button.inn-placed-object .inn-sprite-towelUsed{filter:sepia(.55) saturate(1.25) brightness(.8) contrast(1.15)}

/* Guidance after a question appears and after an answer (app.js guideTo). */
@keyframes guide-glow{
  0%,100%{box-shadow:0 0 0 0 rgba(255,200,90,0)}
  30%,70%{box-shadow:0 0 0 5px rgba(255,200,90,.85),0 0 22px 6px rgba(255,190,80,.55)}
}
.guide-pulse{animation:guide-glow 1.3s ease-in-out 2;border-radius:14px}
@media(prefers-reduced-motion:reduce){
  .guide-pulse{animation:none;box-shadow:0 0 0 4px rgba(255,200,90,.85)}
}

/* "How to interact" folded behind a small ? button (app.js foldHowTo). */
.inn-instruction.how-ready,.inn-stage .inn-instruction.how-ready,.entrance-control-help.how-ready{
  display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;padding:0;border:0;background:transparent;box-shadow:none;margin:0 0 8px}
.inn-stage .inn-instruction.how-ready::before{content:none}
.how-ready .inn-instruction-jp{flex:1 1 auto;margin:0}
.how-help-btn{display:inline-flex;align-items:center;gap:6px;min-height:32px;padding:4px 12px;border:1px solid rgba(203,145,85,.6);
  border-radius:999px;background:rgba(38,22,14,.55);color:#f1dfbd;font:inherit;font-size:12px;font-weight:700;cursor:pointer}
.how-help-btn span{display:inline-grid;place-items:center;width:18px;height:18px;border-radius:50%;background:#f3c568;color:#2b1f14;font-weight:900;font-size:12px}
.how-help-btn[aria-expanded="true"]{background:rgba(243,197,104,.18)}
.how-help-btn{position:relative}
.how-help-btn::before{content:"";position:absolute;inset:-6px 0}
.how-help-text{flex:1 1 100%;padding:8px 12px;border:1px solid rgba(203,145,85,.34);border-radius:10px;background:rgba(38,22,14,.72);
  color:#f1dfbd;font-size:13px;line-height:1.4}
.how-help-text[hidden]{display:none}

/* Daily practice is not a place: no per-place understanding bar. */
#screen-game.practice-stage .mastery-hud{display:none}
.home-tutorial-how{display:flex;align-items:flex-start;gap:8px}
.home-tutorial-how .how-icon{flex:0 0 18px;display:inline-grid;place-items:center;width:18px;height:18px;margin-top:1px;border-radius:50%;background:#f3c568;color:#2b1f14;font-weight:900;font-size:12px}
/* The home's content (room + Kon's panel) is shorter than a tall phone, and
   the frame's full-screen minimum left a dark empty band under it (96px at
   390x844). On phones the frame fits what is in it. */
@media (max-width:760px){
  #screen-game.home-stage{min-height:0}
  #screen-game.home-stage .game-layout{min-height:0}
}
/* The Inn's top bar took 246px of a 390x844 phone before the question.
   The journey sentence repeats what the Training / Shift tabs under it show,
   and 学ぶからやり直す wrapped into a tall two-line pill. */
@media (max-width:760px){
  .inn-stage .inn-journey-status{display:none}
  .inn-stage #btn-restart-learn{min-height:36px;padding:4px 12px;font-size:12px;white-space:nowrap;line-height:1.2}
  .inn-stage .stage-restart::before{inset:-4px 0}
}
.feedback-board-link{display:flex;width:100%;margin:6px 0 8px;text-decoration:none;justify-content:center}
/* The card's link colour (light gold) made the label nearly vanish on the gold button. */
#feedback-panel .feedback-board-link,#feedback-panel .feedback-board-link:hover{color:#2b1f14}
