:root {
  --petal-bg: #fdfaf6;
  --petal-surface: #ffffff;
  --petal-ink: #3a2e2e;
  --petal-muted: #8a7d7d;
  --petal-primary: #d96c9c;
  --petal-primary-dark: #b84f80;
  --petal-primary-light: #f4c6dc;
  --petal-bud: #f6c94c;
  --petal-bud-dark: #e0a92a;
  --petal-leaf: #7fb37a;
  --petal-border: #f0d9e4;
  --petal-hint-fill: #fbf1d3;
  --petal-shadow: 0 4px 14px rgba(217, 108, 156, 0.15);
  --radius-lg: 20px;
  --radius-md: 14px;
  /* Shared target width for Delete/Shuffle/Enter/mult-tracker/hint --
     "Shuffle" is the longest label of the group, so this is sized to fit
     it comfortably and everything else matches. */
  --control-width: 104px;
}

* {
  box-sizing: border-box;
  /* Suppress the default gray tap-highlight flash on iOS/Android for our
     custom-clickable elements (SVG board regions, letters); real feedback
     is handled explicitly (button :active states, board.js's tap effects). */
  -webkit-tap-highlight-color: transparent;
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--petal-bg);
  color: var(--petal-ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  /* App-like feel, not a webpage: no text selection, no long-press callout
     menu, and no double-tap-to-zoom. touch-action must live here (not just
     on the viewport meta tag) because iOS ignores maximum-scale=1 for
     double-tap zoom on later versions -- this CSS property is what actually
     suppresses it. */
  touch-action: manipulation;
  /* App column is a fixed 100dvh with overflow:hidden, but the mobile
     dynamic toolbar can leave the body transiently over-scrollable by a
     pixel -- without this a tap the browser reads as the start of that
     scroll gets its click cancelled (dropped letter taps on the board). */
  overscroll-behavior: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  /* Without this, iOS Safari auto-inflates rem/em text when the user has
     a larger accessibility text size set in Settings, which grows the
     em/rem-sized chrome (word display, hint area, buttons, etc.) inside
     the fixed 100dvh app column and squeezes the board's flex space. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

img {
  -webkit-user-drag: none;
  user-drag: none;
}

.app {
  max-width: 640px;
  margin: 0 auto;
  /* viewport-fit=cover (see base.html) lets the page draw into the notch /
     home-indicator zones, so we pad back out of them. max() keeps a 16px
     floor in normal Safari (where the insets are 0 and the toolbar is the
     buffer) and expands to the ~34px home-indicator gap when running as an
     iOS home-screen web app, where there's no toolbar below the buttons. */
  padding: max(env(safe-area-inset-top), 16px) 16px max(env(safe-area-inset-bottom), 16px);
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-top: 4px;
  flex-shrink: 0;
}

.app-header h1 {
  font-size: 1.35rem;
  font-weight: 700;
  margin: 0;
  color: var(--petal-primary-dark);
  /* Matches .icon-btn's fixed 34px so a browser-boosted font (e.g. Chrome
     iOS's Text Size accessibility setting, which scales rendered font-size
     independent of the declared unit) can't grow this line and stretch
     .app-header taller -- any overflow clips instead of pushing the fixed
     100dvh column's other rows around and shrinking the board. */
  line-height: 34px;
  max-height: 34px;
  overflow: hidden;
  white-space: nowrap;
}

.header-title-group {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

/* Preview mode's "Preview" header label doubles as the way back to the
   theme editor -- styled identically to the plain wordmark it replaces so
   the only visible difference in preview really is the word itself. */
#header-label a {
  color: inherit;
  text-decoration: none;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.icon-btn {
  font-family: inherit;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  overflow: hidden;
  border: none;
  border-radius: 999px;
  background: var(--petal-primary-light);
  color: var(--petal-primary-dark);
  font-weight: 700;
  font-size: 1rem;
  cursor: pointer;
  transition: background-color 0.15s ease;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.icon-btn:focus-visible {
  background: var(--petal-primary);
  color: #fff;
}

@media (hover: hover) and (pointer: fine) {
  .icon-btn:hover {
    background: var(--petal-primary);
    color: #fff;
  }
}

.preview-level-label {
  min-width: 20px;
  text-align: center;
  font-weight: 700;
  color: var(--petal-primary-dark);
}

.theme-credit {
  margin: 2px 0 0;
  font-size: 0.75rem;
  color: var(--petal-muted);
  text-align: right;
}

.theme-credit a {
  color: inherit;
}

.pill-btn {
  font-family: inherit;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Matches .icon-btn's explicit 34px so the header bubbles read as the
     same diameter -- padding+line-height alone (the old sizing) landed a
     little taller and didn't line up. */
  height: 34px;
  overflow: hidden;
  background: var(--petal-primary-light);
  color: var(--petal-primary-dark);
  font-weight: 700;
  padding: 0 16px;
  border: none;
  border-radius: 999px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.15s ease;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.pill-btn:focus-visible {
  background: var(--petal-primary);
  color: #fff;
}

/* Real hover only applies on devices with an actual pointer (mouse/trackpad).
   Touch browsers simulate :hover on tap and never fire a "leave" event, so
   scoping this out avoids buttons getting stuck highlighted after a tap. */
@media (hover: hover) and (pointer: fine) {
  .pill-btn:hover {
    background: var(--petal-primary);
    color: #fff;
  }
}

.score-badge {
  /* Sized for the worst case ("Score: " + 3 digits) so the bubble doesn't
     visibly resize as an in-progress score climbs from 1 to 3 digits --
     it's most jarring early in a game, right as a new player is getting
     their bearings. */
  min-width: 6.5rem;
}

.game-screen {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  gap: 6px;
}

.game-screen[hidden] {
  display: none;
}

.word-display {
  /* Fixed px (not em) and capped with overflow:hidden so a browser-boosted
     font (e.g. Chrome iOS's Text Size accessibility setting, which scales
     rendered font-size independent of the declared unit) can't grow this
     box. It's an overlay on .board-topbar now, not a flow row, but the
     fixed size still matters: board.js reserves .board-topbar's measured
     height off the top of the flower's fit band. */
  height: 51px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  white-space: nowrap;
  text-align: center;
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--petal-ink);
  flex-shrink: 0;
  /* game.js shrinks font-size inline when a long word would overflow this
     fixed-width box; ease the change so letters don't jump on each keypress. */
  transition: font-size 0.08s ease, color 0.15s ease;
}

/* game.js sets .is-pangram when the current input covers every board letter:
   the word turns accent pink, matching the score readout below it
   (.score-preview.is-pangram), as a cue the pangram multiplier is in play. */
.word-display.is-pangram {
  color: var(--petal-primary);
}

.score-preview {
  /* Explicit height (not min-height) so the box occupies the same space
     whether it's empty or holding text, and board.js's reserved
     .board-topbar height stays constant. Fixed px (not em) plus
     overflow:hidden so a browser-boosted font can't grow it -- see
     .word-display above. */
  height: 20px;
  overflow: hidden;
  margin-top: -4px;
  text-align: center;
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--petal-ink);
  transition: color 0.15s ease;
}

/* Set by game.js when the current input covers every board letter: the word
   would score length x pangramMultiplier, so the readout goes bold accent to
   match the Pangram chip lighting up (.mult-tracker.is-applied). */
.score-preview.is-pangram {
  font-weight: 800;
  color: var(--petal-primary);
}

/* The board is the anchor of the screen: board-container (board.css) is
   absolutely positioned and bleeds edge-to-edge, and board.js sizes the
   flower to fill the width, centered. The other UI sits in the space the
   ~square flower leaves: .board-topbar (word readout) overlays the top,
   .controls-panel overlays the bottom -- both over a gradient scrim so the
   art fades out behind them instead of being hard-clipped. */
.board-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
}

/* Word readout + score preview, overlaid on the top of the board rather
   than taking a flow row above it -- a ~1:1 flower centered in a taller
   board-wrap leaves clear space up here, and the scrim keeps the text
   legible if a short screen pushes the petals up under it. board.js
   reserves this element's measured height off the top of the fit band so
   the centered flower doesn't collide with the readout on short screens. */
.board-topbar {
  position: absolute;
  /* Matches .board-container's -16px bleed so the scrim covers the full
     width of the art; the text keeps its inset via the padding. */
  left: -16px;
  right: -16px;
  top: 0;
  z-index: 1;
  padding: 2px 32px 0;
  text-align: center;
  pointer-events: none;
  background: linear-gradient(to bottom, var(--petal-bg) 0, var(--petal-bg) 55%, transparent 100%);
}

.controls-panel {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 6px;
  /* 56px is the panel-chips' own footprint (6px top offset + 50px height,
     see .panel-chip) -- the extra 16px on top of that is breathing room
     between the chips and the buttons below, which would otherwise
     touch exactly (widened from 8px after reports of mis-taps between
     Hint and Delete). */
  padding-top: 72px;
  /* Buffer below the button row, roughly matching .progress-segment's own
     height, now that the progress bar no longer sits here to provide that
     breathing room itself. */
  padding-bottom: 10px;
  background: linear-gradient(to bottom, transparent 0, var(--petal-bg) 56px, var(--petal-bg) 100%);
  /* Only the actual controls should catch clicks -- the transparent/fading
     top of this panel sits over the flower and must let taps through. */
  pointer-events: none;
}

.controls-panel > * {
  pointer-events: auto;
}

/* Shared "chip" shape for the two overlay controls above the
   delete/shuffle/enter row -- same size, padding, and label/value layout so
   they read as a matched pair with aligned bottoms, rather than two
   differently-sized controls. Color is what tells them apart: the pangram
   tracker is a read-only info chip, the hint button an actionable one. Both
   are pulled out of the flex flow and pinned to controls-panel's own top
   edge (6px into it) so they sit inside the panel's transparent top padding
   -- the zone where the flower art shows through before the background
   fades to solid -- rather than pushing the button row down to share a row
   with them. */
.panel-chip {
  position: absolute;
  top: 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: var(--control-width);
  height: 50px;
  overflow: hidden;
  padding: 6px 12px;
  border: none;
  border-radius: var(--radius-md);
  font-family: inherit;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.chip-label {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.chip-value {
  font-size: 1.4rem;
  font-weight: 800;
  transition: transform 0.15s ease;
}

.mult-tracker {
  right: 0;
  background: var(--petal-primary-light);
  color: var(--petal-primary-dark);
  /* Inset ring (0 width at rest) rather than a border, so .is-applied can
     thicken it without shifting the chip's fixed-height inner layout. */
  box-shadow: inset 0 0 0 0 var(--petal-primary-dark);
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

/* game.js adds this while the in-progress word is a pangram: the chip keeps
   its pale info-chip fill (deliberately NOT the solid accent of the Enter
   button) and instead gets a solid accent ring + slight scale -- it reads as
   "this value is being applied", not "tap me". No glow. */
.mult-tracker.is-applied {
  box-shadow: inset 0 0 0 2px var(--petal-primary-dark);
  /* top-right origin so the grow stays inside the viewport edge (right: 0). */
  transform-origin: top right;
  transform: scale(1.04);
}

.mult-tracker.is-applied .chip-value {
  transform: scale(1.08);
}

/* Same idle/hover/active colors as the regular .btn controls (Delete/
   Shuffle/Enter) -- the only difference is the border, which uses the
   yellow the status row fills with (.status-area.has-hint) instead of
   the standard pink, as a color cue tying this button to what it does. */
.hint-btn-overlay {
  left: 0;
  background: var(--petal-surface);
  color: var(--petal-ink);
  border: 2px solid var(--petal-hint-fill);
  cursor: pointer;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.05s ease;
}

/* game.js sets .is-empty when the player has no hints to spend: instead of
   the crisp white surface + yellow cue border of the actionable state, the
   button flattens into a pale bud-yellow wash with muted gold text and no
   visible border -- an inert on-brand chip, not a tappable button. It's also
   `disabled`, so the :active/:hover fills below are guarded off here. */
.hint-btn-overlay.is-empty {
  background: var(--petal-hint-fill);
  border-color: var(--petal-hint-fill);
  color: var(--petal-bud-dark);
  cursor: default;
}

.hint-btn-overlay:not(.is-empty):active,
.hint-btn-overlay:not(.is-empty).is-pressed {
  background: var(--petal-primary-light);
  transform: scale(0.97);
}

@media (hover: hover) and (pointer: fine) {
  .hint-btn-overlay:not(.is-empty):hover {
    background: var(--petal-primary-light);
  }
}

/* The revealed-pangram hint and the transient feedback message share this
   one fixed row (game.js's renderStatus): the hint is the resting content,
   a message overwrites it briefly then it reverts. height (not min-height)
   + overflow:hidden is deliberate -- status-area sits above board-wrap, so
   any height change here reshuffles how much space board-wrap has left, and
   board.js only recomputes the flower's fit on update()/shuffle()/refit(),
   not on every reflow. A fixed height keeps board-wrap constant whether or
   not there's text. */
.status-area {
  display: flex;
  align-items: center;
  justify-content: center;
  /* px, not em -- see .word-display's comment above for why. */
  height: 27px;
  overflow: hidden;
  text-align: center;
  /* A wrapped 2nd line would get cut off mid-line by the fixed height above
     (worse than truncating) -- force one line and ellipsize instead. */
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--petal-bud-dark);
  background: transparent;
  border-radius: var(--radius-md);
  padding: 0 14px;
  transition: background-color 0.15s ease;
  flex-shrink: 0;
}

/* Resting state: showing the revealed-pangram hint. */
.status-area.has-hint {
  background: var(--petal-hint-fill);
}

/* A transient message is showing instead of the hint. */
.status-area.has-message {
  color: var(--petal-primary-dark);
  background: var(--petal-primary-light);
}

/* Cherry-blossom (🌸) level-up messages swap to the yellow palette -- the
   blossom glyph is nearly invisible on the pink pill. Rosette/white flower
   stay pink (they read fine there). */
.status-area.has-message.msg-bud {
  color: var(--petal-bud-dark);
  background: var(--petal-hint-fill);
}

.controls-row {
  display: flex;
  justify-content: center;
  gap: 10px;
  /* nowrap, not wrap: a wrapped 3rd button turns this into a 2nd row,
     growing .controls-panel's height -- board.js reserves that measured
     height off the bottom of the flower's fit band, so a wrap here directly
     shrinks the board. See .primary-controls .btn below for how the buttons
     avoid wrapping instead of overflowing. */
  flex-wrap: nowrap;
  flex-shrink: 0;
}

/* Delete/Shuffle/Enter matched to the same width as the mult-tracker/hint
   chips above them (--control-width, sized to fit "Shuffle") so all five
   controls line up into a tidy grid instead of each hugging its own
   label's width -- on any viewport with enough room (every device seen so
   far) flex-grow:0 keeps that exact 104px width, identical to a fixed
   `width`. flex-shrink:1 is the difference: on a narrowed effective
   viewport (e.g. iOS Display Zoom, which reports a smaller layout viewport
   width rather than boosting font size) where 3*104px + 2*10px gaps no
   longer fits, the three buttons shrink together instead of the row
   wrapping. min-width:0 overrides the flex-item default min-content floor
   so they're actually free to shrink; .btn's overflow:hidden + white-space:
   nowrap then clips a label gracefully rather than reflowing. */
.primary-controls .btn {
  flex: 0 1 var(--control-width);
  min-width: 0;
  padding-left: 10px;
  padding-right: 10px;
}

.btn {
  font-family: inherit;
  font-size: 1rem;
  font-weight: 700;
  padding: 14px 20px;
  /* height (not min-height) + flex-centering + overflow:hidden -- a
     browser-boosted font (e.g. Chrome iOS's Text Size accessibility
     setting, which scales rendered font-size independent of the declared
     unit) would otherwise grow this row past 48px via min-height, and
     .controls-panel's measured height feeds directly into board.js's
     board-space reservation, shrinking the board. */
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  white-space: nowrap;
  border-radius: var(--radius-md);
  border: 2px solid var(--petal-border);
  background: var(--petal-surface);
  color: var(--petal-ink);
  cursor: pointer;
  touch-action: manipulation;
  transition: background-color 0.15s ease, transform 0.05s ease;
  /* A long-press on a button shouldn't select its label text or pop up
     iOS's copy/lookup callout -- neither is useful on a button. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* .btn sets display:flex, which has the same specificity as the UA
   [hidden] rule and comes later in the cascade -- without this, a
   `<button class="btn" hidden>` (e.g. #countdown-ready on the win screen)
   stays visible despite the hidden attribute. */
.btn[hidden] {
  display: none;
}

/* .is-pressed is the JS-driven press state (game.js's bindControlTap): it
   mirrors :active but is applied on pointerdown and held for a short minimum,
   so a quick tap still shows feedback where :active on touch would flash too
   briefly to see -- or not fire at all on iOS. */
.btn:active,
.btn.is-pressed {
  background: var(--petal-primary-light);
  transform: scale(0.97);
}

.btn-primary {
  background: var(--petal-primary);
  border-color: var(--petal-primary);
  color: #fff;
}

.btn-primary:active,
.btn-primary.is-pressed {
  background: var(--petal-primary-dark);
}

/* Real hover only applies on devices with an actual pointer (mouse/trackpad).
   Touch browsers simulate :hover on tap and never fire a "leave" event, so
   scoping this out avoids buttons getting stuck highlighted after a tap. */
@media (hover: hover) and (pointer: fine) {
  .btn:hover {
    background: var(--petal-primary-light);
  }

  .btn-primary:hover {
    background: var(--petal-primary-dark);
  }
}

.btn-secondary {
  font-size: 0.9rem;
  font-weight: 600;
  padding: 10px 16px;
  height: 40px;
  color: var(--petal-ink);
  background: var(--petal-surface);
}

/* A flex column: heading/subtitle/word-list sit at natural size at the top,
   then any vertical space actually left over centers the share/countdown/
   stats cluster below the list (see the auto margins on .win-actions and
   .stats-block) instead of letting it collect as dead space above the share
   button. Reacts to actual available space (screen size, browser chrome,
   orientation) automatically, no JS/resize-handler required. overflow-y:
   auto here stays as a last-resort fallback for screens too short to fit
   even the list's own min-height floor. */
.win-screen {
  background: var(--petal-surface);
  border: 2px solid var(--petal-border);
  border-radius: var(--radius-lg);
  padding: 16px 16px;
  text-align: center;
  box-shadow: var(--petal-shadow);
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.win-screen > * {
  flex-shrink: 0;
}

.win-screen[hidden] {
  display: none;
}

.win-screen h2 {
  margin: 0;
  font-size: 1.3rem;
  color: var(--petal-primary-dark);
}

.win-title-row {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 0 4px;
}

/* Sits at the top-left of the title row (above the words it blurs) rather
   than in flow, so the heading stays visually centered regardless of the
   button's width. Deliberately plain -- no circle/background/color change,
   just the icon -- toggling is communicated entirely by which SVG (open
   vs. slashed eye, swapped in game.js via the [hidden] attribute) is
   showing. */
.blur-toggle-btn {
  position: absolute;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: none;
  background: none;
  color: var(--petal-muted);
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.blur-toggle-btn:active {
  opacity: 0.6;
}

.eye-icon[hidden] {
  display: none;
}

.win-subtitle {
  margin: 0;
  font-size: 0.85rem;
  color: var(--petal-muted);
}

.app-footer {
  flex-shrink: 0;
  /* No top margin -- the credit line sits flush at the top of its own box
     so the space it used to reserve above itself goes back to the results
     card (.win-screen, flex:1). The small bottom padding stacks on top of
     .app's safe-area padding so the line never hugs the screen edge / home
     indicator in a standalone iOS web app. */
  margin: 0;
  padding-bottom: 6px;
  text-align: center;
  font-size: 0.75rem;
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--petal-muted);
  opacity: 0.7;
}

.app-footer[hidden] {
  display: none;
}

.ranked-words-list {
  list-style: none;
  margin: 20px 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  text-align: left;
  max-height: 50vh;
  overflow-y: auto;
}

/* Scroll affordance for the win-screen results list: fade whichever edge has
   hidden content beyond it. JS (game.js) toggles the two classes on scroll /
   resize; with both fades at 0 the mask is fully opaque and invisible. The
   mask tracks the element's own viewport, not the scrolled content, so the
   fade stays pinned to the visible top/bottom edges. */
.ranked-words-list {
  --rw-fade-top: 0px;
  --rw-fade-bottom: 0px;
  -webkit-mask-image: linear-gradient(
    to bottom,
    transparent 0,
    #000 var(--rw-fade-top),
    #000 calc(100% - var(--rw-fade-bottom)),
    transparent 100%
  );
  mask-image: linear-gradient(
    to bottom,
    transparent 0,
    #000 var(--rw-fade-top),
    #000 calc(100% - var(--rw-fade-bottom)),
    transparent 100%
  );
}

.ranked-words-list.can-scroll-up {
  --rw-fade-top: 22px;
}

.ranked-words-list.can-scroll-down {
  --rw-fade-bottom: 28px;
}

/* Sized to its own content rather than forced to grow -- a short list would
   otherwise be stretched to fill the card, leaving a dead gap at its own
   bottom. Instead the leftover card height collects as one gap below the
   list (see .win-actions' margin-top:auto). flex-shrink stays on so a long
   list still gives way first: it shrinks toward min-height and scrolls
   internally, with win-screen's own overflow-y:auto as the final fallback
   if even that floor doesn't fit. The 50vh cap from the base rule is
   dropped here so a long list can use all the room down to the lower
   cluster before it has to start scrolling. */
.win-screen .ranked-words-list {
  flex: 0 1 auto;
  min-height: 90px;
  max-height: none;
  margin: 8px 0 2px;
}

/* Sits just below the results list (under its bottom scroll-fade), above the
   share/stats cluster -- opens the "Explore today's words" panel. */
.win-explore {
  /* A touch more space below than above -- separates the link from the
     share prompt that follows (the space comes back off the feedback
     line's reserve below the Share button). */
  margin: 0 0 13px;
  text-align: center;
}

.win-explore .win-link {
  font-size: 0.78rem;
}

/* Periodic nudge so the (genuinely useful) insights panel doesn't get
   overlooked as a plain text link -- mostly idle, with a quick wiggle every
   few seconds. Runs via a plain animation (not JS) so it starts/stops for
   free whenever .win-screen itself is shown/hidden. */
@keyframes explore-wiggle {
  0%, 85%, 100% { transform: rotate(0deg); }
  87% { transform: rotate(-4deg); }
  89% { transform: rotate(4deg); }
  91% { transform: rotate(-3deg); }
  93% { transform: rotate(3deg); }
  95% { transform: rotate(-1deg); }
}

.win-explore .win-link {
  display: inline-block;
  animation: explore-wiggle 4.5s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .win-explore .win-link {
    animation: none;
  }
}

.win-link {
  padding: 0;
  background: none;
  border: none;
  font: inherit;
  font-weight: 600;
  color: var(--petal-primary-dark);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
  white-space: nowrap;
}

.ranked-words-list li {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 14px;
  background: var(--petal-bg);
  border-radius: var(--radius-md);
  border: 1px solid var(--petal-border);
}

.rw-word {
  font-weight: 700;
  letter-spacing: 0.03em;
}

/* Toggled by the eye button (game.js) so a player can screenshot their
   results without spoiling the specific words -- points (.rw-points,
   untouched here) stay legible. The mask (same fade-to-transparent
   technique as .ranked-words-list's own scroll fade above) tapers the
   blurred word to nothing at its left/right ends, instead of the blur
   just stopping at the text's tight bounding box, which otherwise reads
   as a hard edge. */
.ranked-words-list.is-blurred .rw-word {
  filter: blur(7px);
  -webkit-user-select: none;
  user-select: none;
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 20%, #000 80%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 20%, #000 80%, transparent 100%);
}

.rw-points {
  color: var(--petal-primary-dark);
  font-weight: 700;
}

.rw-points-group {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Static "tap for more" cue on the end-screen word rows -- :hover already
   signals this on a mouse, but touch has no hover, so this stays visible
   on every device instead of relying on it. Decorative only (aria-hidden):
   the whole .petal-row-btn is the tap target, not this icon by itself. */
.rw-info-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  border-radius: 999px;
  background: var(--petal-primary-light);
  color: var(--petal-primary-dark);
  font-size: 0.68rem;
  font-weight: 700;
  font-style: italic;
  line-height: 1;
}

.ranked-words-list li.rw-empty {
  justify-content: center;
  color: var(--petal-muted);
  font-weight: 600;
}

/* Word-detail panel entry point: .petal-row-btn (base.css, shared with
   Unusual Blooms) takes over the card look .ranked-words-list li normally
   draws, so that li is reset to a bare wrapper here -- same treatment as
   .pangrams-list li.petal-row. */
.ranked-words-list li.petal-row {
  display: block;
  padding: 0;
  background: none;
  border: none;
}

.win-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* No gap -- inter-item spacing is set per child. margin-top:auto drops
     this whole lower cluster (prompt / flowers / share / accolade / stats /
     countdown all follow it in source order) to the bottom of the card as
     one block, so any leftover card height collects in a single gap right
     below the word list -- giving the list breathing room -- instead of
     opening up between the histogram and the countdown. */
  margin-top: auto;
  margin-bottom: 2px;
}

/* Matches .stats-summary sizing/color so the prompt reads as the same tier of
   small print as the community-stats line below the countdown. */
.share-prompt {
  margin: 0 0 6px;
  text-align: center;
  color: var(--petal-muted);
  font-weight: 600;
  font-size: clamp(0.56rem, 3vw, 0.82rem);
}

.share-prompt strong {
  color: var(--petal-primary);
  font-weight: 700;
}

/* margin-bottom is the gap before the Share button. */
.flower-row {
  margin: 0 0 10px;
  text-align: center;
  font-size: 1.4rem;
  line-height: 1.1;
  letter-spacing: 2px;
}

.share-feedback {
  color: var(--petal-primary-dark);
  font-weight: 600;
  font-size: 0.85rem;
  min-height: 0.7em;
}

/* Single compact row (label + value inline) instead of a stacked block --
   this used to be the single biggest chunk of dead vertical space on the
   win screen, forcing a scroll just to reach the histogram below it. */
.countdown-wrap {
  margin: 4px 0 0;
  padding: 6px 14px;
  background: var(--petal-bg);
  border-radius: var(--radius-md);
  border: 1px solid var(--petal-border);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 4px 8px;
}

.countdown-label {
  margin: 0;
  color: var(--petal-muted);
  font-weight: 600;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.countdown-value {
  font-size: 1rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--petal-primary-dark);
}

#countdown-ready {
  flex-basis: 100%;
  margin: 4px 0 2px;
}

/* Sits just above the community-stats line. Deliberately louder than
   .stats-summary (accent colour, heavier weight) so it reads as a reward,
   not just another stat. */
.rank-accolade {
  margin: 4px 0 0;
  text-align: center;
  color: var(--petal-primary-dark);
  font-weight: 700;
  font-size: clamp(0.72rem, 3.4vw, 0.95rem);
}

.stats-block {
  margin-top: 4px;
}

.stats-summary {
  color: var(--petal-muted);
  font-weight: 600;
  /* Shrinks on narrow phones so the full "X% finished · avg · top" line
     never wraps to a second line -- clamp() scales it down smoothly
     instead of a fixed breakpoint. Floor is low enough to still fit if
     avg/top ever reach 4-digit scores. */
  font-size: clamp(0.56rem, 3vw, 0.82rem);
  white-space: nowrap;
  margin: 0 0 6px;
}

.histogram {
  width: 100%;
}

.histogram-svg {
  width: 100%;
  height: auto;
}

.hist-bar {
  fill: var(--petal-primary-light);
}

.hist-bar.is-player {
  fill: var(--petal-primary);
  stroke: var(--petal-primary-dark);
  stroke-width: 2px;
}

.hist-avg-line {
  stroke: var(--petal-muted);
  stroke-width: 1.5px;
  stroke-dasharray: 3 2;
}

.hist-avg-label {
  fill: var(--petal-muted);
  font-size: 10px;
  font-weight: 700;
  text-anchor: middle;
}

/* Score printed under the player's highlighted bar (mirrors .hist-avg-label
   under the average line). text-anchor is set inline so it can flip to
   start/end when the bar is at the edge of the chart. */
.hist-player-label {
  fill: var(--petal-primary-dark);
  font-size: 10px;
  font-weight: 700;
}

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(58, 46, 46, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  z-index: 10;
}

.modal-overlay[hidden] {
  display: none;
}

.modal-panel {
  background: var(--petal-surface);
  border: 2px solid var(--petal-border);
  border-radius: var(--radius-lg);
  padding: 24px 20px;
  text-align: center;
  box-shadow: var(--petal-shadow);
  width: 100%;
  max-width: 420px;
  max-height: 80vh;
  overflow-y: auto;
}

/* Desktop-only "copy share text" panel. #share-panel itself is a
   .modal-overlay (dimmed backdrop, centered, click-outside-to-close --
   see base rule above and the click/Escape handlers in game.js) so it reads
   as the focused, primary thing on screen, matching how-to-play/words/
   insights instead of a passive side widget. */
.share-panel-panel {
  position: relative; /* anchor for the absolutely-positioned close button */
  max-width: 320px;
}

.share-panel-close {
  position: absolute;
  top: 12px;
  left: 12px;
}

.share-panel-title {
  /* Left-padding clears the corner close button; matching right padding
     keeps the title visually centered in the remaining space rather than
     drifting right. */
  margin: 0 0 14px;
  padding: 0 40px;
  color: var(--petal-primary-dark);
  font-size: 1.1rem;
}

.share-panel-text {
  width: 100%;
  margin: 0 0 14px;
  padding: 10px;
  border: 2px solid var(--petal-border);
  border-radius: var(--radius-md);
  background: var(--petal-bg);
  color: var(--petal-ink);
  font-family: inherit;
  font-size: 0.9rem;
  line-height: 1.4;
  white-space: pre-wrap;
  resize: none;
}

.share-panel-copy-btn {
  /* .btn is a block-level flex container but sizes to its content
     (form-control shrink-to-fit), so it isn't centered by the panel's
     text-align:center the way inline content is -- margin:auto centers the
     box itself within the available width. */
  margin: 0 auto;
}

/* Reserve the "Copied!" line's height up front (min-height alone doesn't
   apply to the feedback span's default inline display) so the panel doesn't
   grow/shift when the message appears after a copy. */
.share-panel-feedback {
  display: block;
  min-height: 1.2em;
  margin-top: 8px;
}

.modal-panel h2 {
  margin-top: 0;
  color: var(--petal-primary-dark);
}

.pangrams-list {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.pangrams-list li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 10px 14px;
  background: var(--petal-bg);
  border: 1px solid var(--petal-border);
  border-radius: var(--radius-md);
}

.pangram-count {
  color: var(--petal-muted);
  font-weight: 600;
  font-size: 0.85rem;
}

.pangram-word {
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--petal-primary-dark);
}

/* "Explore today's words" panel -- a multi-section modal with a header that
   labels the content below and prev/next arrows to page between sections.
   Fixed height (not content-sized) so the header + arrows never shift as you
   page between sections with different amounts of content; the body scrolls
   and any leftover height is dead space above the Close button. */
.insights-panel {
  height: min(80vh, 560px);
  max-height: none;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.insights-panel > * {
  flex-shrink: 0;
}

.insights-nav {
  display: flex;
  /* Pin the arrows to the top of the heading block so they land in the same
     spot on every section, regardless of how many lines the subtitle wraps to. */
  align-items: start;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 16px;
}

.insights-heading {
  flex: 1;
  min-width: 0;
}

.insights-heading h2 {
  margin: 0;
  /* Center the 34px arrows against the title line. */
  min-height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.insights-subtitle {
  margin: 4px 0 0;
  color: var(--petal-muted);
  font-size: 0.9rem;
}

.insights-dots {
  display: flex;
  justify-content: center;
  gap: 6px;
  margin-top: 6px;
}

.insights-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--petal-muted);
  opacity: 0.35;
  transition: opacity 0.16s ease, transform 0.16s ease;
}

.insights-dot.is-active {
  opacity: 1;
  background: var(--petal-primary-dark);
  transform: scale(1.3);
}

/* Only one section available: no need to indicate position. */
.insights-nav--single .insights-dots {
  visibility: hidden;
}

.insights-nav .icon-btn:disabled {
  opacity: 0.3;
  cursor: default;
}

/* Only one section available (crowd stats still locked): keep the arrows in
   the layout so the heading stays centered, but make them inert/invisible. */
.insights-nav--single .icon-btn {
  visibility: hidden;
}

.insights-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  margin-bottom: 10px;
}

.insights-body .pangrams-list {
  margin: 0;
}

/* Word-detail panel only: unlike the insights panel's sections (each their
   own page, no need for trailing space), the stats list here is followed by
   the pie-chart bubble on the same page, so it needs its bottom margin back. */
#word-detail-page .pangrams-list {
  margin: 0 0 8px;
}

/* Slide/fade transition between sections (arrows or swipe) -- game.js swaps
   this element's class list to animate the outgoing content off to the side
   it's leaving from, swaps in the new section's markup, then animates it in
   from the opposite edge. */
.insights-page {
  transition: transform 0.16s ease, opacity 0.16s ease;
}

.insights-anim-out-left {
  transform: translateX(-18px);
  opacity: 0;
}

.insights-anim-out-right {
  transform: translateX(18px);
  opacity: 0;
}

.insights-anim-in-left,
.insights-anim-in-right {
  transition: none;
}

.insights-anim-in-left {
  transform: translateX(-18px);
  opacity: 0;
}

.insights-anim-in-right {
  transform: translateX(18px);
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .insights-page {
    transition: none;
  }
}

.insight-value {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
}

/* Cherry blossom marking a pangram, sits just left of the word. */
.insights-pangram {
  font-size: 0.85em;
  line-height: 1;
}

.insights-check {
  color: var(--petal-primary-dark);
  font-weight: 700;
}

/* Unusual Blooms row: the whole card is the vote toggle (not just the small
   flower icon) so it's easy to hit on mobile. .petal-row-btn takes over the
   card look .pangrams-list li normally draws, so that li is reset to a bare
   wrapper here. */
.pangrams-list li.petal-row {
  display: block;
  padding: 0;
  background: none;
  border: none;
}

.petal-row-btn {
  display: flex;
  width: 100%;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 10px 14px;
  background: var(--petal-bg);
  border: 1px solid var(--petal-border);
  border-radius: var(--radius-md);
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.petal-row-btn:active,
.petal-row-btn.is-pressed {
  transform: scale(0.98);
}

@media (hover: hover) and (pointer: fine) {
  .petal-row-btn:hover {
    border-color: var(--petal-primary);
  }
}

.petal-control {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* Visual-only circle -- the whole row is the tap target now, not this icon. */
.petal-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border: 1.5px solid var(--petal-border);
  border-radius: 999px;
  font-size: 0.8rem;
  line-height: 1;
}

.petal-row-btn.is-voted .petal-icon {
  border-color: var(--petal-primary);
  background: var(--petal-bg);
}

.petal-count {
  min-width: 1.2em;
  color: var(--petal-muted);
  font-weight: 600;
  font-size: 0.85rem;
}

.insights-topscore-head {
  margin: 0 0 4px;
  font-weight: 700;
  color: var(--petal-primary-dark);
}

/* "K-letter flower" divider -- opens each flower's word(s) in both the hints
   and top-score sections. */
.insights-group-head {
  margin: 14px 0 6px;
  text-align: left;
  color: var(--petal-muted);
  font-weight: 700;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.insights-topscore-head + .insights-group-head,
.insights-page > .insights-group-head:first-child {
  margin-top: 0;
}

.insights-empty {
  margin: 0;
  color: var(--petal-muted);
  font-size: 0.9rem;
}

/* Key for the row markers, pinned below the scrolling body. */
.insights-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px 16px;
  margin: 0 0 14px;
  color: var(--petal-muted);
  font-size: 0.72rem;
  font-weight: 600;
}

.insights-legend .insights-check {
  color: var(--petal-primary-dark);
}

.icon-btn.is-pressed {
  background: var(--petal-primary);
  color: #fff;
}

/* Word-detail panel: the pie chart shows a word's points (hatched) nested
   inside its flower's points (solid) out of the player's total game score
   (the neutral track). Same hue for the flower slice and its word segment
   on purpose -- the hatch pattern is the only thing telling them apart, so
   the chart is always paired with the named legend beside it (.wd-pie-legend). */
/* Same card look as .pangrams-list li's stat rows, so the pie chart reads as
   one more bubble in the same set rather than a separately-styled block. */
.wd-pie-row {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 14px;
  padding: 12px 14px;
  background: var(--petal-bg);
  border: 1px solid var(--petal-border);
  border-radius: var(--radius-md);
  margin: 0 0 14px;
}

.wd-pie-wrap {
  flex: 0 0 auto;
  width: 108px;
}

.wd-pie-svg {
  display: block;
  width: 100%;
  height: auto;
}

.wd-pie-track {
  fill: var(--petal-muted);
  fill-opacity: 0.22;
}

/* The rest of the flower is a plain solid pink; the word's own wedge is the
   same pink with a yellow hatch on top, so it reads as "this flower, plus a
   highlight on this word" rather than a second, different-colored slice. */
.wd-pie-level {
  fill: var(--petal-primary);
}

/* The word wedge itself: hatched fill, plus an outline in the hatch's own
   yellow so the boundary between it and the plain-pink rest-of-flower wedge
   reads clearly even where the hatching alone is subtle. */
.wd-pie-word {
  fill: url(#wd-hatch-word);
  stroke: var(--petal-bud);
  stroke-width: 2px;
  stroke-linejoin: round;
}

.wd-hatch-bg-word {
  fill: var(--petal-primary);
}

.wd-hatch-line-word {
  stroke: var(--petal-bud);
  stroke-width: 2px;
}

/* Names + values for the track/level/word slices -- the pie chart's color
   and texture are never the only thing carrying meaning. */
.wd-pie-legend {
  list-style: none;
  margin: 0;
  padding: 0;
  flex: 1 1 140px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.82rem;
  /* .modal-panel sets text-align:center; each row's own flex layout handles
     swatch/label/value positioning, but the label span (flex:1, wider than
     its own text) would otherwise inherit that and center its text within
     the extra width instead of sitting flush left. */
  text-align: left;
}

/* Word above its score/percentage instead of squeezed onto one line beside
   it -- a long word plus "N pts (M%)" has nowhere near enough room to share
   a row without truncating the word down to a couple of letters. */
.wd-pie-legend li {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.wd-pie-legend-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.wd-pie-legend-label {
  min-width: 0;
  overflow-wrap: anywhere;
  font-weight: 600;
}

.wd-pie-legend-value {
  margin-left: 22px; /* lines up under the label text, past the swatch + gap */
  color: var(--petal-muted);
  font-weight: 600;
}

.wd-swatch {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  border-radius: 4px;
}

.wd-swatch-track {
  background: var(--petal-muted);
  opacity: 0.22;
}

/* Matches the pie chart's own two hatch patterns in miniature. */
.wd-swatch-level {
  background: var(--petal-primary);
}

/* Matches the pie chart's own word-wedge pattern: pink with a yellow hatch. */
.wd-swatch-word {
  background: repeating-linear-gradient(
    45deg,
    var(--petal-primary),
    var(--petal-primary) 2px,
    var(--petal-bud) 2px,
    var(--petal-bud) 3px
  );
}

.wd-pie-caption {
  margin: 0 0 14px;
  color: var(--petal-muted);
  font-size: 0.82rem;
  text-align: center;
}

.wd-badges {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  margin: 0 0 14px;
}

.wd-badge {
  padding: 4px 10px;
  background: var(--petal-primary-light);
  color: var(--petal-primary-dark);
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.72rem;
}


.htp-panel {
  text-align: left;
}

.htp-panel h2 {
  text-align: center;
}

.htp-tldr {
  margin: 0 0 16px;
  font-size: 0.95rem;
  line-height: 1.4;
}

.htp-tldr strong {
  color: var(--petal-primary-dark);
}

.htp-list {
  margin: 0 0 16px;
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 0.95rem;
  line-height: 1.4;
}

.htp-list strong {
  color: var(--petal-primary-dark);
}

.htp-example {
  background: var(--petal-bg);
  border: 1px solid var(--petal-border);
  border-radius: var(--radius-md);
  padding: 10px 14px;
  font-size: 0.9rem;
  line-height: 1.4;
  margin: 0 0 20px;
}

.htp-example strong {
  color: var(--petal-primary-dark);
}

.htp-legend {
  background: var(--petal-bg);
  border: 1px solid var(--petal-border);
  border-radius: var(--radius-md);
  padding: 10px 14px;
  margin: 0 0 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.htp-legend-title {
  margin: 0;
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--petal-primary-dark);
}

.htp-legend-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.85rem;
  line-height: 1.35;
}

.htp-legend-row strong {
  color: var(--petal-primary-dark);
}

.htp-legend-emoji {
  font-size: 1.3rem;
  flex-shrink: 0;
}

#btn-close-how-to-play {
  display: block;
  margin: 0 auto;
}

.htp-contact {
  margin: 16px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--petal-border);
  text-align: center;
  font-size: 0.8rem;
  color: var(--petal-text-muted, #666);
}

.htp-contact a,
.htp-contact .link-button {
  color: var(--petal-primary-dark);
  font-weight: 600;
}

.link-button {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
}

.link-button.is-copied {
  text-decoration: none;
}

/* "Cramped mode": toggled on <html> by game.js's updateCrampedMode() when
   the flower's true available band is uncomfortably small (very short
   screens + real accessibility text-size boosting, or a mobile browser
   toolbar eating extra height on first paint). Reclaims real vertical
   space -- not just clipping -- so board.js's MIN_FLOWER_BAND_PX floor
   rarely has to be what keeps the flower off the controls. Every rule here
   keeps real tap targets (chips, buttons) at/above ~40px; text-only rows
   (header title, word readout, status row) shrink further since they're
   never tapped. Every selector is scoped under html.is-cramped, so this
   block has zero effect unless that class is present. */
html.is-cramped .app {
  gap: 4px;
}

html.is-cramped .game-screen {
  gap: 4px;
}

html.is-cramped .app-header {
  padding-top: 0;
}

html.is-cramped .app-header h1 {
  font-size: 1.05rem;
  line-height: 26px;
  max-height: 26px;
}

html.is-cramped .word-display {
  font-size: 1.5rem;
  height: 38px;
}

html.is-cramped .score-preview {
  height: 16px;
  font-size: 0.8rem;
}

html.is-cramped .status-area {
  height: 20px;
  font-size: 0.85rem;
}

html.is-cramped .controls-panel {
  /* Matches the shrunk .panel-chip below: 6px top offset + 40px chip
     height + 10px breathing room, down from the default 72px (6+50+16). */
  padding-top: 56px;
  padding-bottom: 4px;
}

html.is-cramped .panel-chip {
  height: 40px;
  padding: 4px 10px;
}

html.is-cramped .chip-value {
  font-size: 1.15rem;
}

html.is-cramped .primary-controls .btn {
  height: 42px;
}

@media (min-width: 640px) {
  .app-header h1 {
    font-size: 1.6rem;
  }

  .word-display {
    font-size: 2.4rem;
    height: 61px;
  }
}
